﻿using AutoMapper;
using IOA.MES.Common;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using IOA.MES.Log.Business;
using IOA.MES.Log.DataAccess.VModel;
using IOA.Utils;
using NLog;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;

namespace IOA.MES.Business
{
    /// <summary>
    /// 工单管理（错误代码：102001）
    /// </summary>
    public class WorkOrderMgr
    {
        private MESContext mesDb = new MESContext("MES");
        private Logger logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 查询车间工单
        /// </summary>
        public Tuple<int, List<VWorkOrder>> QueryWorkshopWorkOrders(int page, int limit, string workshopCode)
        {
            var query = mesDb.WorkOrders.AsNoTracking().Where(_ => _.WorkshopCode == workshopCode && _.Valid);
            var total = query.Count();
            var skip = (page - 1) * limit;
            query = query.OrderByDescending(_ => _.PkId);
            var entities = page <= 0 ? query.ToList() : query.Skip(skip).Take(limit).ToList();
            return new Tuple<int, List<VWorkOrder>>(total, Mapper.Map<List<VWorkOrder>>(entities));
        }

        /// <summary>
        /// 获取最新条码
        /// </summary>
        public string GetNewBarCode(int machineId, string workOrderNo, int @operator)
        {
            var machine = mesDb.Machines.AsNoTracking().FirstOrDefault(_ => _.PkId == machineId && _.Valid);
            var distributeCode = mesDb.DistributeCodes.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.LineId == machine.LineId && _.Status == DistributeCodeStatus.UnPrinted && _.Valid)
                .OrderBy(_ => _.PkId).FirstOrDefault();
            if (distributeCode == null)
            {
                throw new MultiLanBizException(102039, workOrderNo);//该工单在当前产线已没有已分片、未打印的条码
            }
            mesDb.DistributeCodes.Attach(distributeCode);
            distributeCode.Status = DistributeCodeStatus.Printed;
            distributeCode.ModifyBy = @operator;
            distributeCode.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            return distributeCode.Code;
        }

        /// <summary>
        /// 核验补打权限
        /// </summary>
        public void CheckRePrintBarCode(string userName, string password, string workOrderNo, string barCode)
        {
            var user = new UserMgr().GetUser(0, userName);
            if (user == null)
            {
                throw new MultiLanBizException(105001, userName);//用户名不存在
            }
            else if (!user.Roles.Any(_ => _.PkId == 1) && !user.Roles.Any(_ => string.Equals(_.RoleName, "条码补打员")))
            {
                throw new MultiLanBizException(102040);//您无权补打条码
            }

            var component = new ComponentMgr().GetComponent(barCode);
            if (component == null)
            {
                throw new MultiLanBizException(137002, barCode);//条码不存在
            }
            else if (!string.Equals(component.WorkOrderNo, workOrderNo, StringComparison.CurrentCultureIgnoreCase))
            {
                throw new MultiLanBizException(102041);//当前条码不是该工单的条码
            }
            else if (!user.Workshops.Any(_ => string.Equals(_.WorkshopCode, component.WorkshopCode, StringComparison.CurrentCultureIgnoreCase)))
            {
                throw new MultiLanBizException(102042, component.WorkshopName);//您没有当前工单所在车间的权限
            }
        }


        /// <summary>
        /// 编辑工单
        /// </summary>
        /// <param name="model">工单对象</param>
        public void EditWorkOrder(VWorkOrder model)
        {
            var entity = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.PkId == model.PkId && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(102002);// $"工单不存在或已被删除，无法修改");
            }

            mesDb.WorkOrders.Attach(entity);
            entity.CellQuantity = model.CellQuantity;
            entity.CellLevel = model.CellLevel;
            entity.CellModel = model.CellModel;
            entity.CellEfficiencyMin = model.CellEfficiencyMin;
            entity.CellEfficiencyMax = model.CellEfficiencyMax;
            entity.SingleCellPower = model.SingleCellPower;
            entity.Remark = model.Remark;

            var qLevels = mesDb.WorkOrderQLevels.AsNoTracking().Where(_ => _.WorkOrderNo == model.WorkOrderNo && _.Valid).ToList();
            model.QLevels.ForEach(_ =>
            {
                _.WorkOrderNo = model.WorkOrderNo;
                _.OrderNo = model.OrderNo;
                _.QLevel = $"Q{model.QLevels.IndexOf(_) + 1}";
                _.CreateBy = model.CreateBy;
                _.CreateTime = DateTime.Now;
            });
            var newLevels = model.QLevels.Where(level => !qLevels.Select(_ => _.QLevel).Contains(level.QLevel, StringComparer.CurrentCultureIgnoreCase)).ToList();
            var removeLevels = qLevels.Where(level => !model.QLevels.Select(_ => _.QLevel).Contains(level.QLevel, StringComparer.CurrentCultureIgnoreCase)).ToList();
            var updateLevels = qLevels.Where(level => model.QLevels.Select(_ => _.QLevel).Contains(level.QLevel, StringComparer.CurrentCultureIgnoreCase)).ToList();
            mesDb.WorkOrderQLevels.AddRange(Mapper.Map<List<WorkOrderQLevel>>(newLevels));
            removeLevels.ForEach(_ =>
            {
                mesDb.WorkOrderQLevels.Attach(_);
                _.Valid = false;
                _.ModifyBy = model.ModifyBy;
                _.ModifyTime = DateTime.Now;
            });
            updateLevels.ForEach(_ =>
            {
                var newLevel = model.QLevels.FirstOrDefault(level => StringUtils.Equals(level.QLevel, _.QLevel));
                mesDb.WorkOrderQLevels.Attach(_);
                _.ProductCode = newLevel.ProductCode;
                _.ProductName = newLevel.ProductName;
                _.ModifyBy = model.ModifyBy;
                _.ModifyTime = DateTime.Now;
            });

            var powers = mesDb.WorkOrderOutputPowers.AsNoTracking().Where(_ => _.WorkOrderNo == model.WorkOrderNo && _.Valid).ToList();
            var newPowers = model.OutputPowers.Where(level => !powers.Select(_ => _.OutputPower).Contains(level.OutputPower)).ToList();
            var removePowers = powers.Where(level => !model.OutputPowers.Select(_ => _.OutputPower).Contains(level.OutputPower)).ToList();
            newPowers.ForEach(_ =>
            {
                _.OrderNo = entity.OrderNo;
                _.WorkOrderNo = entity.WorkOrderNo;
                _.CreateBy = model.CreateBy;
                _.CreateTime = DateTime.Now;
            });
            removePowers.ForEach(_ =>
            {
                mesDb.WorkOrderOutputPowers.Attach(_);
                _.Valid = false;
                _.ModifyBy = model.ModifyBy;
                _.ModifyTime = DateTime.Now;
            });
            mesDb.WorkOrderOutputPowers.AddRange(Mapper.Map<List<WorkOrderOutputPower>>(newPowers));

            var workOrderBinningPowers = mesDb.WorkOrderBinningSchemas.AsNoTracking().Where(_ => _.WorkOrderNo == model.WorkOrderNo && _.Valid).ToList();
            var newBinningPowerIds = model.BinningPowers.Where(p => !workOrderBinningPowers.Select(_ => _.BinningPowerId).Contains(p.PkId)).Select(_ => _.PkId).ToList();
            var removeBinningPowerIds = workOrderBinningPowers.Where(p => !model.BinningPowers.Select(_ => _.PkId).Contains(p.BinningPowerId)).ToList();
            removeBinningPowerIds.ForEach(_ =>
            {
                mesDb.WorkOrderBinningSchemas.Attach(_);
                _.Valid = false;
                _.ModifyBy = model.ModifyBy;
                _.ModifyTime = DateTime.Now;
            });
            if (newBinningPowerIds.Any())
            {
                var binningPowers = mesDb.BinningPowers.AsNoTracking().Where(_ => newBinningPowerIds.Contains(_.PkId) && _.Valid).ToList();
                mesDb.WorkOrderBinningSchemas.AddRange(newBinningPowerIds.Select(powerId => new WorkOrderBinningSchema
                {
                    BinningPowerId = powerId,
                    OrderNo = entity.OrderNo,
                    WorkOrderNo = entity.WorkOrderNo,
                    BinningSchemeId = binningPowers.FirstOrDefault(_ => _.PkId == powerId)?.SchemaId ?? 0,
                    NameplateModel = binningPowers.FirstOrDefault(_ => _.PkId == powerId)?.NameplateModel,
                    BinningPower = binningPowers.FirstOrDefault(_ => _.PkId == powerId)?.Power ?? 0,
                    CreateBy = model.ModifyBy,
                    CreateTime = DateTime.Now
                }));
            }

            mesDb.SaveChanges();
        }

        /// <summary>
        /// 查询单号列表
        /// </summary>
        /// <param name="noType">类型（0：订单号，1：工单号）</param>
        /// <param name="workshopCode">车间代码</param>
        /// <param name="key">关键字</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">截止时间</param>
        /// <returns>单号列表</returns>
        public List<string> QueryNos(int noType, string workshopCode, string key, DateTime? startTime, DateTime? endTime)
        {
            var query = mesDb.ProductViaSiteRecords.AsNoTracking().Where(_ => _.Valid);
            if (!string.IsNullOrWhiteSpace(workshopCode))
            {
                query = query.Where(_ => _.WorkshopCode == workshopCode);
            }
            if (!string.IsNullOrWhiteSpace(key))
            {
                if (noType == 0)
                {
                    query = query.Where(_ => _.OrderNo.Contains(key));
                }
                else
                {
                    query = query.Where(_ => _.WorkOrderNo.Contains(key));
                }
            }
            if (startTime.HasValue && endTime.HasValue)
            {
                query = query.Where(_ => _.CreateTime >= startTime.Value && _.CreateTime < endTime.Value);
            }

            var nos = noType == 0 ? query.Select(_ => _.OrderNo).Distinct().ToList()
                : query.Select(_ => _.WorkOrderNo).Distinct().ToList();

            return nos.OrderBy(_ => _).ToList();
        }

        /// <summary>
        /// 获取工单
        /// </summary>
        /// <param name="WorkOrderId">工单ID</param>
        public VWorkOrder GetWorkOrder(int WorkOrderId)
        {
            var entity = mesDb.WorkOrders.FirstOrDefault(_ => _.PkId == WorkOrderId && _.Valid);
            var model = Mapper.Map<VWorkOrder>(entity);
            if (model != null)
            {
                var order = mesDb.Orders.FirstOrDefault(_ => _.InnerOrderNo == model.InnerOrderNo);
                model.CustomerCode = order.CustomerCode;
                model.CustomerName = order.CustomerName;
            }
            return model;
        }

        /// <summary>
        /// 获取工单
        /// </summary>
        /// <param name="workOrderNo">工单号</param>
        public VWorkOrder GetWorkOrder(string workOrderNo)
        {
            var entity = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == workOrderNo && _.Valid);
            var model = Mapper.Map<VWorkOrder>(entity);
            if (model != null)
            {
                var order = mesDb.Orders.AsNoTracking().FirstOrDefault(_ => _.InnerOrderNo == model.InnerOrderNo);
                model.CustomerCode = order?.CustomerCode;
                model.CustomerName = order?.CustomerName;

                var levels = mesDb.WorkOrderQLevels.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).ToList();
                var powers = mesDb.WorkOrderOutputPowers.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).ToList();
                model.QLevels = Mapper.Map<List<VWorkOrderQLevel>>(levels).OrderBy(_ => _.QLevel).ToList();
                model.OutputPowers = Mapper.Map<List<VWorkOrderOutputPower>>(powers).OrderBy(_ => _.OutputPower).ToList();
                var workOrderPowerIds = mesDb.WorkOrderBinningSchemas.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).Select(_ => _.BinningPowerId).ToList();
                var binningPowers = mesDb.BinningPowers.AsNoTracking().Where(_ => workOrderPowerIds.Contains(_.PkId) && _.Valid).ToList();
                model.BinningPowers = Mapper.Map<List<VBinningPower>>(binningPowers);
                model.BinningPowers.ForEach(power =>
                {
                    power.Currents = Mapper.Map<List<VBinningCurrent>>(mesDb.BinningCurrents.AsNoTracking().Where(_ => _.PowerId == power.PkId && _.Valid).ToList());
                });
            }
            return model;
        }

        /// <summary>
        /// 获取工单
        /// </summary>
        /// <param name="workOrderNo">工单号</param>
        public VWorkOrder GetWorkOrderWithBoms(string workOrderNo)
        {
            var entity = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == workOrderNo && _.Valid);
            var model = Mapper.Map<VWorkOrder>(entity);
            if (model != null)
            {
                var boms = mesDb.WorkOrderBoms.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).OrderBy(_ => _.PkId).ToList();
                model.Boms = Mapper.Map<List<VWorkOrderBom>>(boms);
            }
            return model;
        }

        /// <summary>
        /// 查询工单列表
        /// </summary>
        /// <param name="pageIndex">页面索引</param>
        /// <param name="pageSize">页面容量</param>
        /// <param name="total">全部数量</param>
        /// <param name="workshopCodes">车间代码</param>
        /// <param name="orderNo">订单号</param>
        /// <param name="workOrderNo">工单号</param>
        /// <param name="startTime">下单开始日期</param>
        /// <param name="endTime">下单截止日期</param>
        /// <returns>工单列表</returns>
        public List<VWorkOrder> QueryWorkOrders(int pageIndex, int pageSize, out int total, List<string> workshopCodes, string orderNo, string workOrderNo, ProduceStatus? status, DateTime? startTime, DateTime? endTime, bool isReport = false)
        {
            if (!workshopCodes.Any())
            {
                total = 0;
                return new List<VWorkOrder>();
            }
            var query = mesDb.WorkOrders.Where(_ => workshopCodes.Contains(_.WorkshopCode) && _.Valid);

            var workOrderNos = (workOrderNo ?? string.Empty).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(_ => _.ToUpper().Trim()).Distinct().ToList();
            if (workOrderNos.Any())
            {
                workOrderNo = workOrderNos[0];
                query = workOrderNos.Count == 1 ? query.Where(_ => _.WorkOrderNo == workOrderNo) : query.Where(_ => workOrderNos.Contains(_.WorkOrderNo));
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(orderNo))
                {
                    orderNo = orderNo.Trim();
                    query = query.Where(_ => _.OrderNo == orderNo);
                }
                if (startTime.HasValue)
                {
                    query = query.Where(_ => _.WorkOrderTime >= startTime.Value);
                }
                if (endTime.HasValue)
                {
                    query = query.Where(_ => _.WorkOrderTime < endTime);
                }
                if (status.HasValue)
                {
                    query = query.Where(_ => _.Status == status.Value);
                }
            }

            total = query.Count();
            query = query.OrderByDescending(_ => _.PkId);
            var entities = pageSize <= 0 ? query.ToList() : query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            var models = Mapper.Map<List<VWorkOrder>>(entities);
            var innerOrderNos = models.Select(_ => _.InnerOrderNo).Distinct().ToList();
            workOrderNos = models.Select(_ => _.WorkOrderNo).Distinct().ToList();
            var orders = mesDb.Orders.Where(_ => innerOrderNos.Contains(_.InnerOrderNo)).ToList();
            var outputs = mesDb.WorkOrderOutputPowers.AsNoTracking().Where(_ => workOrderNos.Contains(_.WorkOrderNo) && _.Valid).ToList();
            var schemas = (from schema in mesDb.WorkOrderBinningSchemas.AsNoTracking()
                           join power in mesDb.BinningPowers.AsNoTracking() on schema.BinningPowerId equals power.PkId
                           where schema.Valid && workOrderNos.Contains(schema.WorkOrderNo) && power.Valid
                           select new
                           {
                               schema.WorkOrderNo,
                               power
                           }).ToList();
            models.ForEach(workOrder =>
            {
                workOrder.CustomerCode = orders.FirstOrDefault(_ => string.Equals(_.InnerOrderNo, workOrder.InnerOrderNo, StringComparison.CurrentCultureIgnoreCase))?.CustomerCode ?? string.Empty;
                workOrder.CustomerName = orders.FirstOrDefault(_ => string.Equals(_.InnerOrderNo, workOrder.InnerOrderNo, StringComparison.CurrentCultureIgnoreCase))?.CustomerName ?? string.Empty;
                workOrder.OutputPowers = Mapper.Map<List<VWorkOrderOutputPower>>(outputs.Where(_ => string.Equals(_.WorkOrderNo, workOrder.WorkOrderNo, StringComparison.CurrentCultureIgnoreCase)).ToList());
                workOrder.BinningPowers = Mapper.Map<List<VBinningPower>>(schemas.Where(_ => string.Equals(_.WorkOrderNo, workOrder.WorkOrderNo, StringComparison.CurrentCultureIgnoreCase)).Select(_ => _.power).ToList());
                if (isReport)
                {
                    workOrder.DistributeQuantity = mesDb.Components.AsNoTracking().Count(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.DistributeTime.HasValue && _.Valid);
                    workOrder.LaminatedQuantity = mesDb.Components.AsNoTracking().Count(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.LaminatedTime.HasValue && _.Valid);
                    workOrder.PackQuantity = mesDb.Components.AsNoTracking().Count(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.PackTime.HasValue && _.Valid);
                    workOrder.InboundQuantity = mesDb.Components.AsNoTracking().Count(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.InboundTime.HasValue && _.Valid);
                    workOrder.InboundRate = workOrder.DistributeQuantity <= 0 ? 0 : (decimal)workOrder.InboundQuantity / workOrder.DistributeQuantity;
                }
            });
            return models;
        }

        /// <summary>
        /// 获取入库检
        /// </summary>
        /// <param name="inspectId">入库检ID</param>
        /// <returns>入库检对象</returns>
        public VInboundInspect GetInboundInspect(int inspectId)
        {
            var entity = mesDb.InboundInspects.FirstOrDefault(_ => _.PkId == inspectId && _.Status != PackInboundInspectStatus.CancelInspect && _.Valid);
            if (entity == null)
            {
                return null;
            }
            var model = Mapper.Map<VInboundInspect>(entity);
            var products = mesDb.InboundInspectProducts.AsNoTracking().Where(_ => _.InspectId == inspectId && _.Valid).ToList();
            model.Products = Mapper.Map<List<VInboundInspectProduct>>(products);
            return model;
        }

        /// <summary>
        /// 获取入库检
        /// </summary>
        /// <param name="packNo">打包编号</param>
        /// <returns>入库检对象</returns>
        public VInboundInspect GetInboundInspect(string packNo)
        {
            var entity = mesDb.InboundInspects.FirstOrDefault(_ => _.PackNo == packNo && _.Status != PackInboundInspectStatus.CancelInspect && _.Valid);
            if (entity == null)
            {
                return null;
            }
            var model = Mapper.Map<VInboundInspect>(entity);
            var products = mesDb.InboundInspectProducts.AsNoTracking().Where(_ => _.InspectId == entity.PkId && _.Valid).ToList();
            model.Products = Mapper.Map<List<VInboundInspectProduct>>(products);
            return model;
        }

        /// <summary>
        /// 查询分片条码
        /// </summary>
        /// <param name="pageIndex">页面索引</param>
        /// <param name="pageSize">页面容量</param>
        /// <param name="total">全部数量</param>
        /// <param name="distributeTaskId">任务ID</param>
        /// <param name="status">状态</param>
        /// <param name="code">条码</param>
        /// <returns>条码列表</returns>
        public List<VDistributeCode> QueryWorkOrderDistributeCodes(int pageIndex, int pageSize, out int total, int distributeTaskId, DistributeCodeStatus? status, string code)
        {
            var query = mesDb.DistributeCodes.Where(_ => _.DistributeTaskId == distributeTaskId && _.Valid);
            if (status.HasValue)
            {
                query = query.Where(_ => _.Status == status.Value);
            }
            if (!string.IsNullOrWhiteSpace(code))
            {
                query = query.Where(_ => _.Code.Contains(code));
            }

            total = query.Count();

            query = query.OrderBy(_ => _.PkId);

            var entities = pageSize <= 0 ? query.ToList() : query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();

            return Mapper.Map<List<VDistributeCode>>(entities);
        }

        /// <summary>
        /// 分片条码操作
        /// </summary>
        /// <param name="model">操作任务</param>
        /// <param name="codeIds">条码ID列表</param>
        /// <param name="onlyOperateValid">只操作有效的（打印全部、打印未打印的，回收全部、回收未生产的）</param>
        /// <returns>操作对象</returns>
        public VDistributeCodeOperateTask DistributeCodeOperate(VDistributeCodeOperateTask model, List<int> codeIds, bool operateAll = true)
        {
            var codeEntities = mesDb.DistributeCodes.AsNoTracking().Where(_ => codeIds.Contains(_.PkId) && _.Valid).ToList();

            if (model.OperateType == DistributeCodeOperateType.Print
                || model.OperateType == DistributeCodeOperateType.ForcePrint)
            {
                var printed = codeEntities.Where(_ => new[] { DistributeCodeStatus.Printed, DistributeCodeStatus.Produced }.Contains(_.Status)).ToList();
                //既非打印有效 && 非强制打印
                if (printed.Any() && operateAll && model.OperateType != DistributeCodeOperateType.ForcePrint)
                {
                    throw new MultiLanBizException(102004, string.Join("、", printed.Select(_ => _.Code).Distinct()));// $"本次任务存在重复打印条码：{string.Join("、", printed.Select(_ => _.Code).Distinct())}");
                }
                else
                {
                    var operates = new List<DistributeCodeOperate>();
                    foreach (var _ in codeEntities.Where(code => code.Status == DistributeCodeStatus.UnPrinted).ToList())
                    {
                        operates.Add(new DistributeCodeOperate
                        {
                            CodeId = _.PkId,
                            Code = _.Code,
                            OperateType = DistributeCodeOperateType.Print,
                            CreateBy = model.CreateBy,
                            CreateTime = DateTime.Now
                        });
                        mesDb.DistributeCodes.Attach(_);
                        _.Status = DistributeCodeStatus.Printed;
                    }

                    if (operateAll)
                    {
                        operates.AddRange(codeEntities.Where(code => new[] { DistributeCodeStatus.Printed, DistributeCodeStatus.Produced }.Contains(code.Status)).Select(_ => new DistributeCodeOperate
                        {
                            CodeId = _.PkId,
                            Code = _.Code,
                            OperateType = DistributeCodeOperateType.ForcePrint,
                            CreateBy = model.CreateBy,
                            CreateTime = DateTime.Now
                        }));
                    }

                    if (!operates.Any())
                    {
                        throw new MultiLanBizException(102005);//$"本次没有需要打印的条码"
                    }

                    var entity = Mapper.Map<DistributeCodeOperateTask>(model);
                    mesDb.DistributeCodeOperateTasks.Add(entity);
                    mesDb.SaveChanges();

                    operates.ForEach(_ => _.TaskId = entity.PkId);
                    mesDb.DistributeCodeOperates.AddRange(operates);
                    mesDb.SaveChanges();

                    model = Mapper.Map<VDistributeCodeOperateTask>(entity);
                }
            }
            else
            {
                var printed = codeEntities.Where(_ => new[] { DistributeCodeStatus.Produced, DistributeCodeStatus.Printed }.Contains(_.Status)).ToList();
                if (printed.Any() && operateAll && model.OperateType != DistributeCodeOperateType.ForceRecycle)
                {
                    throw new MultiLanBizException(102006, string.Join("、", printed.Select(_ => _.Code).Distinct()));// $"本次回收存在已打印的条码：{string.Join("、", printed.Select(_ => _.Code).Distinct())}");
                }
                else
                {
                    var operates = new List<DistributeCodeOperate>();
                    foreach (var _ in codeEntities.Where(code => code.Status == DistributeCodeStatus.UnPrinted).ToList())
                    {
                        operates.Add(new DistributeCodeOperate
                        {
                            CodeId = _.PkId,
                            Code = _.Code,
                            OperateType = DistributeCodeOperateType.Recycle,
                            CreateBy = model.CreateBy,
                            CreateTime = DateTime.Now
                        });
                        mesDb.DistributeCodes.Attach(_);
                        _.Status = DistributeCodeStatus.Recycled;
                    }

                    if (operateAll)
                    {
                        foreach (var _ in codeEntities.Where(code => new[] { DistributeCodeStatus.Printed, DistributeCodeStatus.Produced }.Contains(code.Status)).ToList())
                        {
                            operates.Add(new DistributeCodeOperate
                            {
                                CodeId = _.PkId,
                                Code = _.Code,
                                OperateType = DistributeCodeOperateType.ForceRecycle,
                                CreateBy = model.CreateBy,
                                CreateTime = DateTime.Now
                            });
                            mesDb.DistributeCodes.Attach(_);
                            _.Status = DistributeCodeStatus.Recycled;
                        }
                    }

                    if (!operates.Any())
                    {
                        throw new MultiLanBizException(102007);//$"本次没有需要回收的条码"
                    }

                    var entity = Mapper.Map<DistributeCodeOperateTask>(model);
                    mesDb.DistributeCodeOperateTasks.Add(entity);
                    mesDb.SaveChanges();

                    operates.ForEach(_ => _.TaskId = entity.PkId);
                    mesDb.DistributeCodeOperates.AddRange(operates);

                    var barCodes = operates.Select(_ => _.Code).Distinct().ToList();
                    var components = mesDb.Components.AsNoTracking().Where(_ => barCodes.Contains(_.BarCode) && _.Valid).ToList();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.ProduceStatus = ProduceStatus.Produced;
                        _.ProductStatus = ProductStatus.Recycled;
                        _.ModifyBy = model.CreateBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.SaveChanges();

                    model = Mapper.Map<VDistributeCodeOperateTask>(entity);
                }
            }
            return model;
        }

        /// <summary>
        /// 查询补片记录
        /// </summary>
        public Tuple<int, List<VCompenCellRecord>> QueryCompenCellRecords(int page, int limit, string workshopCode, string workOrderNo,
            CompenProcessType? process, FragmentType? reason, DateTime startTime, DateTime endTime)
        {
            var query = mesDb.CompenCellRecords.AsNoTracking().Where(_ => _.WorkshopCode == workshopCode && _.CreateTime >= startTime && _.CreateTime < endTime);
            if (!string.IsNullOrWhiteSpace(workOrderNo))
            {
                query = query.Where(_ => _.WorkOrderNo == workOrderNo);
            }
            if (process.HasValue)
            {
                query = query.Where(_ => _.CompenProcess == process.Value);
            }
            if (reason.HasValue)
            {
                query = query.Where(_ => _.CompenReason == reason.Value);
            }
            var count = query.Count();
            query = query.OrderBy(_ => _.PkId);
            var skip = (page - 1) * limit;
            var entities = page <= 0 ? query.ToList() : query.Skip(skip).Take(limit).ToList();
            var models = Mapper.Map<List<VCompenCellRecord>>(entities);
            var users = new UserMgr().QueryUsers(entities.Select(_ => _.CreateBy).ToList());
            models.ForEach(model =>
            {
                model.CNCreateBy = users.FirstOrDefault(_ => _.PkId == model.CreateBy)?.TrueName;
            });

            return new Tuple<int, List<VCompenCellRecord>>(count, models);
        }

        /// <summary>
        /// 执行补片
        /// </summary>
        /// <param name="model">补片记录</param>
        public void CompenCell(VCompenCellRecord model)
        {
            var workOrder = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == model.WorkOrderNo && _.Valid);
            if (workOrder == null)
            {
                return;
            }
            var duty = new WorkshopDutyMgr().GetDuty(model.CompenDutyId);
            if (duty == null)
            {
                throw new MultiLanBizException(110027);//当前时间没有班次在工作
            }
            model.WorkshopCode = workOrder.WorkshopCode;
            model.WorkshopName = workOrder.WorkshopName;
            model.CompenDutyId = duty.PkId;
            model.CompenDutyName = duty.DutyName;
            model.OrderNo = workOrder.OrderNo;
            model.CreateTime = DateTime.Now;
            mesDb.CompenCellRecords.Add(Mapper.Map<CompenCellRecord>(model));
            mesDb.SaveChanges();
        }

        /// <summary>
        /// 查询车间工单
        /// </summary>
        /// <param name="workshopCode">车间代码</param>
        /// <returns>工单列表</returns>
        public List<VWorkOrder> QueryWorkOrders(string workshopCode)
        {
            var workOrders = mesDb.WorkOrders.AsNoTracking().Where(_ => _.WorkshopCode == workshopCode && _.Valid).ToList();
            return Mapper.Map<List<VWorkOrder>>(workOrders);
        }

        /// <summary>
        /// 完成打包
        /// </summary>
        /// <param name="model">包装对象</param>
        public void FinishPack(VPack model)
        {
            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            if (pack == null)
            {
                throw new MultiLanBizException(102008, model.PackNo);//包装不存在
            }
            else if (pack.PackStatus == PackStatus.Unpack)
            {
                throw new MultiLanBizException(102009, model.PackNo);//包装已被解除
            }
            else if (pack.PackStatus == PackStatus.Normal)
            {
                throw new MultiLanBizException(102010, model.PackNo);//包装已完成，无法重复操作
            }

            var packProducts = mesDb.PackProducts.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Valid).ToList();
            if (!packProducts.Any())
            {
                throw new MultiLanBizException(102011, model.PackNo);//请至少打包一块组件
            }

            pack.Quantity = packProducts.Select(_ => _.BarCode.Trim().ToUpper()).Distinct().Count();
            pack.PackStatus = PackStatus.Normal;
            pack.ModifyBy = model.ModifyBy;
            pack.ModifyTime = DateTime.Now;
            mesDb.Database.ExecuteSqlCommand($"UPDATE Pack SET Quantity = @Quantity, PackStatus = @PackStatus, ModifyBy = @ModifyBy, ModifyTime = @ModifyTime WHERE Valid = 1 AND PkId = @PkId;",
                new SqlParameter[] {
                    new SqlParameter("Quantity", pack.Quantity),
                    new SqlParameter("PackStatus", (int)pack.PackStatus),
                    new SqlParameter("ModifyBy", pack.ModifyBy),
                    new SqlParameter("ModifyTime", pack.ModifyTime?.ToString("yyyy-MM-dd HH:mm:ss")),
                    new SqlParameter("PkId", pack.PkId),
                });

            #region 添加入库检
            var inspect = new InboundInspect
            {
                PackBatchNo = pack.PackBatchNo,
                PackNo = pack.PackNo,
                Status = PackInboundInspectStatus.UnInspected,
                CreateBy = model.ModifyBy,
                CreateTime = DateTime.Now,
            };
            mesDb.InboundInspects.Add(inspect);
            mesDb.SaveChanges();

            var barCodes = packProducts.Select(_ => _.BarCode).Distinct().ToList();
            var components = mesDb.Components.AsNoTracking().Where(_ => barCodes.Contains(_.BarCode) && _.Valid).ToList();
            var inspectProducts = components.Select(_ => new InboundInspectProduct
            {
                InspectId = inspect.PkId,
                BarCode = _.BarCode,
                QLevel = _.QLevel,
                BoxImage = _.BoxImage,
                EL2Image = _.EL2Image,
                IvImage = _.IvImage,
                OrderNo = _.OrderNo,
                WorkOrderNo = _.WorkOrderNo,
                CreateBy = inspect.CreateBy,
                CreateTime = DateTime.Now,
                Status = InspectProductStatus.UnInspected
            }).ToList();
            mesDb.InboundInspectProducts.AddRange(inspectProducts);
            mesDb.SaveChanges();
            #endregion
        }

        /// <summary>
        /// 打包
        /// </summary>
        public VPack PackProduct(VPackProduct model)
        {
            var component = mesDb.Components.AsNoTracking().FirstOrDefault(_ => _.Valid && _.BarCode == model.BarCode);
            if (component == null)
            {
                throw new MultiLanBizException(102012, model.PackNo);//组件不存在
            }
            else if (component.Locked)
            {
                throw new MultiLanBizException(110016, component.BarCode);//当前组件已锁定，无法过站：
            }
            else if (!string.IsNullOrWhiteSpace(component.PackNo))
            {
                throw new MultiLanBizException(102031, model.PackNo);//当前组件已打入其他包装
            }

            var packCondition = new PackConditionMgr().GetPackCondition(string.Empty, component.WorkOrderNo, StringUtils.Equals(component.QLevel, "Q1") ? QLevelCondition.Q1 : QLevelCondition.NotQ1);
            if (packCondition == null)
            {
                throw new MultiLanBizException(102016, model.PackNo);//当前工单及订单没有配置打包规则
            }

            //组件存在降级未复判记录，不允许打包
            var exsitdowngrade = mesDb.Downgrades.AsNoTracking().FirstOrDefault(_ => _.BarCode == model.BarCode && _.Reviewed == false && _.Valid);
            if (exsitdowngrade != null)
            {
                throw new MultiLanBizException(110036, model.BarCode); //组件存在降级记录，不允许打包
            }

            var packings = mesDb.Packs.AsNoTracking().Where(_ => _.WorkshopCode == model.WorkshopCode && _.PackStatus == PackStatus.Packing && _.Valid)
                .OrderBy(_ => _.PackIndex).ToList();
            Pack pack = null;
            foreach (var packItem in packings)
            {
                if (packItem.Quantity <= 0)
                { }
                else if (packCondition.OrderNoLimit && !StringUtils.Equals(packItem.OrderNo, component.OrderNo))
                {
                    continue;// new MultiLanBizException(102032, $"订单号：{pack.OrderNo}/{component.OrderNo}");//打包规则不匹配，包装参数和当前组件参数分别为：
                }
                else if (packCondition.WorkOrderNoLimit && !StringUtils.Equals(packItem.WorkOrderNo, component.WorkOrderNo))
                {
                    continue;// new MultiLanBizException(102032, $"工单号：{pack.WorkOrderNo}/{component.WorkOrderNo}");
                }
                else if (packCondition.DataPlate && !StringUtils.Equals(packItem.NameplateModel, component.NameplateModel))
                {
                    continue;// new MultiLanBizException(102032, $"铭牌型号：{pack.NameplateModel}/{component.NameplateModel}");
                }
                else if (packCondition.RatedPower && packItem.IVPowerLevel != component.IVPowerLevel)
                {
                    continue;// new MultiLanBizException(102032, $"额定功率：{pack.IVPowerLevel}/{component.IVPowerLevel}");
                }
                else if (packCondition.ElectricGrade && !StringUtils.Equals(packItem.IVCurrentLevel, component.IVCurrentLevel))
                {
                    continue;// new MultiLanBizException(102032, $"电流档：{pack.IVCurrentLevel}/{component.IVCurrentLevel}");
                }
                else if (packCondition.CompGrade && !StringUtils.Equals(packItem.QLevel, component.QLevel))
                {
                    continue;// new MultiLanBizException(102032, $"组件等级：{pack.QLevel}/{component.QLevel}");
                }
                else if (packCondition.CompColor && !StringUtils.Equals(packItem.ComponentColor, component.ComponentColor))
                {
                    continue;// new MultiLanBizException(102032, $"组件颜色：{pack.ComponentColor}/{component.ComponentColor}");
                }
                else if (packCondition.JunBoxFactory && !StringUtils.Equals(packItem.JunBoxFactory, component.JunBoxFactory))
                {
                    continue;// new MultiLanBizException(102032, $"接线盒厂家：{pack.JunBoxFactory}/{component.JunBoxFactory}");
                }
                else if (packCondition.JunBoxSpecs && !StringUtils.Equals(packItem.JunBoxSpecs, component.JunBoxSpecs))
                {
                    continue;// new MultiLanBizException(102032, $"接线盒规格：{pack.JunBoxSpecs}/{component.JunBoxSpecs}");
                }
                else if (packCondition.BackPlanFactory && !StringUtils.Equals(packItem.BackPlanFactory, component.BackPlanFactory))
                {
                    continue;// new MultiLanBizException(102032, $"背板厂家：{pack.BackPlanFactory}/{component.BackPlanFactory}");
                }
                else if (packCondition.BackPlanSpecs && !StringUtils.Equals(packItem.BackPlanSpecs, component.BackPlanSpecs))
                {
                    continue;// new MultiLanBizException(102032, $"背板规格：{pack.BackPlanSpecs}/{component.BackPlanSpecs}");
                }
                else if (packCondition.AluFrameFactory && !StringUtils.Equals(packItem.AluFrameFactory, component.AluFrameFactory))
                {
                    continue;// new MultiLanBizException(102032, $"铝框厂家：{pack.AluFrameFactory}/{component.AluFrameFactory}");
                }
                else if (packCondition.AluFrameSpecs && !StringUtils.Equals(packItem.AluFrameSpecs, component.AluFrameSpecs))
                {
                    continue;// new MultiLanBizException(102032, $"铝框规格：{pack.AluFrameSpecs}/{component.AluFrameSpecs}");
                }
                else if (packCondition.BatteryFactory && !StringUtils.Equals(packItem.BatteryFactory, component.BatteryFactory))
                {
                    continue;// new MultiLanBizException(102032, $"电池片厂家：{pack.BatteryFactory}/{component.BatteryFactory}");
                }
                else if (packCondition.BatterySpecs && !StringUtils.Equals(packItem.BatterySpecs, component.BatterySpecs))
                {
                    continue;// new MultiLanBizException(102032, $"电池片规格：{pack.BatterySpecs}/{component.BatterySpecs}");
                }
                pack = packItem;
                break;
            }
            if (pack == null)
            {
                var index = 0;
                while (true)
                {
                    index++;
                    if (!packings.Any(_ => _.PackIndex == index))
                    {
                        break;
                    }
                }
                return new VPack
                {
                    PackIndex = index
                };
            }

            //正常过站
            var dutyId = 0;
            new ProductViaSiteMgr().ViaSite(new VProductViaSiteRecord
            {
                Code = model.BarCode,
                CreateBy = model.CreateBy,
                DutyId = pack.DutyId,
                DutyName = pack.DutyName,
                MachineId = pack.MachineId,
                MachineName = pack.MachineName,
                OrderNo = pack.OrderNo,
                WorkOrderNo = pack.WorkOrderNo,
                WorkshopCode = pack.WorkshopCode,
                WorkshopName = pack.WorkshopName,
                SiteType = SiteType.Packing,
            }, out dutyId);

            mesDb.Packs.Attach(pack);
            pack.Quantity = pack.Quantity + 1;
            //第一个组件打包时，初始化包装参数
            if (pack.Quantity <= 1)
            {
                pack.OrderNo = component.OrderNo;
                pack.InnerOrderNo = component.OrderNo;
                pack.WorkOrderNo = component.WorkOrderNo;
                pack.ProductCode = component.ProductCode;
                pack.ProductName = component.ProductName;
                pack.ProductSpecs = component.ProductSpecs;
                pack.ModifyBy = model.CreateBy;
                pack.ModifyTime = DateTime.Now;

                pack.CellEfficiency = component.CellEfficiency;
                pack.NameplateModel = component.NameplateModel;
                pack.IVCurrentLevel = component.IVCurrentLevel;
                pack.IVPowerLevel = component.IVPowerLevel;
                pack.PowerRange = component.PowerRange;
                pack.ComponentColor = component.ComponentColor;
                pack.QLevel = component.QLevel;

                pack.JunBoxFactory = component.JunBoxFactory;
                pack.JunBoxSpecs = component.JunBoxSpecs;
                pack.BackPlanFactory = component.BackPlanFactory;
                pack.BackPlanSpecs = component.BackPlanSpecs;
                pack.AluFrameFactory = component.AluFrameFactory;
                pack.AluFrameSpecs = component.AluFrameSpecs;
                pack.BatteryFactory = component.BatteryFactory;
                pack.BatterySpecs = component.BatterySpecs;
                pack.JunBoxCode = component.JunBoxCode;
                pack.ShortFrameCode = component.ShortFrameCode;
                pack.LongFrameCode = component.LongFrameCode;
                pack.BackPlanCode = component.BackPlanCode;
                pack.GlassCode = component.GlassCode;
                pack.GlassFactory = component.GlassFactory;

                pack.CustomerCode = component.CustomerCode;
                pack.CustomerName = component.CustomerName;
            }

            model.WorkshopCode = component.WorkshopCode;
            model.WorkshopName = component.WorkshopName;
            model.OrderNo = component.OrderNo;
            model.WorkOrderNo = component.WorkOrderNo;
            model.PackBatchNo = pack.PackBatchNo;
            model.PackNo = pack.PackNo;
            model.ProductCode = component.ProductCode;
            model.ProductName = component.ProductName;
            model.CreateTime = DateTime.Now;
            model.VerifyCode = component.VerifyCode;
            var entity = Mapper.Map<PackProduct>(model);
            mesDb.PackProducts.Add(entity);
            mesDb.SaveChanges();

            if (packCondition.QuantityLimit.HasValue && packCondition.QuantityLimit.Value <= pack.Quantity)
            {
                FinishPack(new VPack { PackNo = pack.PackNo, ModifyBy = model.CreateBy });
                pack.PackStatus = PackStatus.Normal;
            }

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    #region 处理组件
                    mesDb.Components.Attach(component);
                    component.PackBatchNo = pack.PackBatchNo;
                    component.PackNo = pack.PackNo;
                    component.ModifyBy = model.CreateBy;
                    component.ModifyTime = DateTime.Now;
                    mesDb.SaveChanges();

                    var user = new UserMgr().QueryUsers(new List<int> { model.CreateBy }).FirstOrDefault();
                    var logs = new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = component.BarCode,
                        LogName = "组件打包",
                        LogStatus = "正常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"组件打包",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    };
                    new OprLogMgr().AddLogs(new List<VOprLog> { logs });
                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"打包异常，箱号：{model.PackNo}，异常信息：{ex.Message}");
                }
            });

            return Mapper.Map<VPack>(pack);
        }

        /// <summary>
        /// 打包
        /// </summary>
        /// <param name="model">打包产品对象</param>
        public void PackProduct(VPackProduct model, out VPackCondition packCondition, out VPackProduct packs)
        {
            var component = mesDb.Components.AsNoTracking().FirstOrDefault(_ => _.BarCode == model.BarCode && _.Valid);
            if (component == null)
            {
                throw new MultiLanBizException(102012, model.PackNo);//组件不存在
            }
            else if (component.Locked)
            {
                throw new MultiLanBizException(110016, component.BarCode);//当前组件已锁定，无法过站：
            }

            //组件存在降级未复判记录，不允许打包
            var exsitdowngrade = mesDb.Downgrades.AsNoTracking().FirstOrDefault(_ => _.BarCode == model.BarCode && _.Reviewed == false && _.Valid);
            if (exsitdowngrade != null)
            {
                throw new MultiLanBizException(110036, model.BarCode); //组件存在降级记录，不允许打包
            }

            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            if (pack == null)
            {
                throw new MultiLanBizException(102008, model.PackNo);//包装不存在
            }
            else if (pack.PackStatus == PackStatus.Unpack)
            {
                throw new MultiLanBizException(102009, model.PackNo);//包装已被解除
            }
            else if (pack.PackInspectStatus == PackInboundInspectStatus.Inspected)
            {
                throw new MultiLanBizException(102014, model.PackNo);//入库检已通过，无法继续打包
            }
            else if (pack.StockStatus != PackStockStatus.NotInbound)
            {
                throw new MultiLanBizException(102015, model.PackNo);//包装已入库，无法继续打包
            }

            var packProduct = mesDb.PackProducts.AsNoTracking().FirstOrDefault(_ => _.BarCode == model.BarCode && _.Valid);
            if (packProduct != null)
            {
                throw new MultiLanBizException(102031, model.PackNo);//当前组件已打入其他包装
            }

            #region 打包规则校验
            var curPackProductCount = mesDb.PackProducts.AsNoTracking().Count(_ => _.PackNo == model.PackNo && _.Valid);
            //第2块组件开始校验打包规则
            if (curPackProductCount <= 0)
            {
                packCondition = new PackConditionMgr().GetPackCondition(string.Empty, component.WorkOrderNo, StringUtils.Equals(component.QLevel, "Q1") ? QLevelCondition.Q1 : QLevelCondition.NotQ1);
                if (packCondition == null)
                {
                    throw new MultiLanBizException(102016, model.PackNo);//当前工单及订单没有配置打包规则
                }
            }
            else
            {
                packCondition = new PackConditionMgr().GetPackCondition(string.Empty, pack.WorkOrderNo, StringUtils.Equals(pack.QLevel, "Q1") ? QLevelCondition.Q1 : QLevelCondition.NotQ1);
                if (packCondition == null)
                {
                    throw new MultiLanBizException(102016, model.PackNo);//当前工单及订单没有配置打包规则
                }
                else if (packCondition.QuantityLimit.HasValue && packCondition.QuantityLimit.Value <= curPackProductCount)
                {
                    throw new MultiLanBizException(102017, model.PackNo);//当前打包数量已满
                }
                else if (packCondition.OrderNoLimit && !StringUtils.Equals(pack.OrderNo, component.OrderNo))
                {
                    throw new MultiLanBizException(102032, $"订单号：{pack.OrderNo}/{component.OrderNo}");//打包规则不匹配，包装参数和当前组件参数分别为：
                }
                else if (packCondition.WorkOrderNoLimit && !StringUtils.Equals(pack.WorkOrderNo, component.WorkOrderNo))
                {
                    throw new MultiLanBizException(102032, $"工单号：{pack.WorkOrderNo}/{component.WorkOrderNo}");
                }
                else if (packCondition.DataPlate && !StringUtils.Equals(pack.NameplateModel, component.NameplateModel))
                {
                    throw new MultiLanBizException(102032, $"铭牌型号：{pack.NameplateModel}/{component.NameplateModel}");
                }
                else if (packCondition.RatedPower && pack.IVPowerLevel != component.IVPowerLevel)
                {
                    throw new MultiLanBizException(102032, $"额定功率：{pack.IVPowerLevel}/{component.IVPowerLevel}");
                }
                else if (packCondition.ElectricGrade && !StringUtils.Equals(pack.IVCurrentLevel, component.IVCurrentLevel))
                {
                    throw new MultiLanBizException(102032, $"电流档：{pack.IVCurrentLevel}/{component.IVCurrentLevel}");
                }
                else if (packCondition.CompGrade && !StringUtils.Equals(pack.QLevel, component.QLevel))
                {
                    throw new MultiLanBizException(102032, $"组件等级：{pack.QLevel}/{component.QLevel}");
                }
                else if (packCondition.CompColor && !StringUtils.Equals(pack.ComponentColor, component.ComponentColor))
                {
                    throw new MultiLanBizException(102032, $"组件颜色：{pack.ComponentColor}/{component.ComponentColor}");
                }
                else if (packCondition.JunBoxFactory && !StringUtils.Equals(pack.JunBoxFactory, component.JunBoxFactory))
                {
                    throw new MultiLanBizException(102032, $"接线盒厂家：{pack.JunBoxFactory}/{component.JunBoxFactory}");
                }
                else if (packCondition.JunBoxSpecs && !StringUtils.Equals(pack.JunBoxSpecs, component.JunBoxSpecs))
                {
                    throw new MultiLanBizException(102032, $"接线盒规格：{pack.JunBoxSpecs}/{component.JunBoxSpecs}");
                }
                else if (packCondition.BackPlanFactory && !StringUtils.Equals(pack.BackPlanFactory, component.BackPlanFactory))
                {
                    throw new MultiLanBizException(102032, $"背板厂家：{pack.BackPlanFactory}/{component.BackPlanFactory}");
                }
                else if (packCondition.BackPlanSpecs && !StringUtils.Equals(pack.BackPlanSpecs, component.BackPlanSpecs))
                {
                    throw new MultiLanBizException(102032, $"背板规格：{pack.BackPlanSpecs}/{component.BackPlanSpecs}");
                }
                else if (packCondition.AluFrameFactory && !StringUtils.Equals(pack.AluFrameFactory, component.AluFrameFactory))
                {
                    throw new MultiLanBizException(102032, $"铝框厂家：{pack.AluFrameFactory}/{component.AluFrameFactory}");
                }
                else if (packCondition.AluFrameSpecs && !StringUtils.Equals(pack.AluFrameSpecs, component.AluFrameSpecs))
                {
                    throw new MultiLanBizException(102032, $"铝框规格：{pack.AluFrameSpecs}/{component.AluFrameSpecs}");
                }
                else if (packCondition.BatteryFactory && !StringUtils.Equals(pack.BatteryFactory, component.BatteryFactory))
                {
                    throw new MultiLanBizException(102032, $"电池片厂家：{pack.BatteryFactory}/{component.BatteryFactory}");
                }
                else if (packCondition.BatterySpecs && !StringUtils.Equals(pack.BatterySpecs, component.BatterySpecs))
                {
                    throw new MultiLanBizException(102032, $"电池片规格：{pack.BatterySpecs}/{component.BatterySpecs}");
                }
            }
            #endregion

            //正常过站
            var dutyId = 0;
            new ProductViaSiteMgr().ViaSite(new VProductViaSiteRecord
            {
                Code = model.BarCode,
                CreateBy = model.CreateBy,
                DutyId = pack.DutyId,
                DutyName = pack.DutyName,
                MachineId = pack.MachineId,
                MachineName = pack.MachineName,
                OrderNo = pack.OrderNo,
                WorkOrderNo = pack.WorkOrderNo,
                WorkshopCode = pack.WorkshopCode,
                WorkshopName = pack.WorkshopName,
                SiteType = SiteType.Packing,
            }, out dutyId);

            mesDb.Packs.Attach(pack);
            pack.Quantity = pack.Quantity + 1;
            //第一个组件打包时，初始化包装参数
            if (curPackProductCount <= 0)
            {
                pack.OrderNo = component.OrderNo;
                pack.InnerOrderNo = component.OrderNo;
                pack.WorkOrderNo = component.WorkOrderNo;
                pack.ProductCode = component.ProductCode;
                pack.ProductName = component.ProductName;
                pack.ProductSpecs = component.ProductSpecs;
                pack.ModifyBy = model.CreateBy;
                pack.ModifyTime = DateTime.Now;

                pack.CellEfficiency = component.CellEfficiency;
                pack.NameplateModel = component.NameplateModel;
                pack.IVCurrentLevel = component.IVCurrentLevel;
                pack.IVPowerLevel = component.IVPowerLevel;
                pack.PowerRange = component.PowerRange;
                pack.ComponentColor = component.ComponentColor;
                pack.QLevel = component.QLevel;

                pack.JunBoxFactory = component.JunBoxFactory;
                pack.JunBoxSpecs = component.JunBoxSpecs;
                pack.BackPlanFactory = component.BackPlanFactory;
                pack.BackPlanSpecs = component.BackPlanSpecs;
                pack.AluFrameFactory = component.AluFrameFactory;
                pack.AluFrameSpecs = component.AluFrameSpecs;
                pack.BatteryFactory = component.BatteryFactory;
                pack.BatterySpecs = component.BatterySpecs;
                pack.JunBoxCode = component.JunBoxCode;
                pack.ShortFrameCode = component.ShortFrameCode;
                pack.LongFrameCode = component.LongFrameCode;
                pack.BackPlanCode = component.BackPlanCode;
                pack.GlassCode = component.GlassCode;
                pack.GlassFactory = component.GlassFactory;

                pack.CustomerCode = component.CustomerCode;
                pack.CustomerName = component.CustomerName;


            }

            model.WorkshopCode = component.WorkshopCode;
            model.WorkshopName = component.WorkshopName;
            model.OrderNo = component.OrderNo;
            model.WorkOrderNo = component.WorkOrderNo;
            model.PackBatchNo = pack.PackBatchNo;
            model.PackNo = pack.PackNo;
            model.ProductCode = component.ProductCode;
            model.ProductName = component.ProductName;
            model.CreateTime = DateTime.Now;
            model.VerifyCode = component.VerifyCode;
            var entity = Mapper.Map<PackProduct>(model);
            mesDb.PackProducts.Add(entity);
            mesDb.SaveChanges();

            packs = model;

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    #region 处理组件
                    mesDb.Components.Attach(component);
                    component.PackBatchNo = pack.PackBatchNo;
                    component.PackNo = pack.PackNo;
                    component.ModifyBy = model.CreateBy;
                    component.ModifyTime = DateTime.Now;
                    mesDb.SaveChanges();

                    var user = new UserMgr().QueryUsers(new List<int> { model.CreateBy }).FirstOrDefault();
                    var logs = new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = component.BarCode,
                        LogName = "组件打包",
                        LogStatus = "正常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"组件打包",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    };
                    new OprLogMgr().AddLogs(new List<VOprLog> { logs });
                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"打包异常，箱号：{model.PackNo}，异常信息：{ex.Message}");
                }
            });
        }


        /// <summary>
        /// 解包组件
        /// </summary>
        /// <param name="model">组件对象</param>
        public void UnPackProduct(VPackProduct model)
        {
            var packProduct = mesDb.PackProducts.FirstOrDefault(_ => _.BarCode == model.BarCode && _.Valid);
            if (packProduct == null)
            {
                return;
                //throw new MultiLanBizException(102033, model.BarCode);//当前条码不在包装中
            }
            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == packProduct.PackNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            if (pack.PackStatus == PackStatus.Normal)
            {
                throw new MultiLanBizException(102034, model.BarCode);//当前包装已经完成打包
            }

            mesDb.Packs.Attach(pack);
            pack.Quantity = pack.Quantity - 1;
            mesDb.PackProducts.Attach(packProduct);
            packProduct.Valid = false;
            packProduct.ModifyBy = model.ModifyBy;
            packProduct.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    var component = mesDb.Components.AsNoTracking().FirstOrDefault(_ => _.BarCode == model.BarCode && _.Valid);
                    if (component == null)
                    {
                        throw new MultiLanBizException(102012, model.PackNo);//组件不存在
                    }

                    #region 处理组件
                    mesDb.Components.Attach(component);
                    component.PackBatchNo = string.Empty;
                    component.PackNo = string.Empty;
                    //component.PackTime = null;
                    component.ModifyBy = model.ModifyBy;
                    component.ModifyTime = DateTime.Now;
                    mesDb.SaveChanges();

                    var user = new UserMgr().QueryUsers(new List<int> { model.ModifyBy }).FirstOrDefault();
                    var logs = new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = component.BarCode,
                        LogName = "组件解包",
                        LogStatus = "异常",
                        OpeatorId = model.ModifyBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"单个组件解包",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    };
                    new OprLogMgr().AddLogs(new List<VOprLog> { logs });
                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"解包组件异常，组件条码：{model.BarCode}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 查询检测列表
        /// </summary>
        /// <param name="page">页面索引</param>
        /// <param name="limit">页面容量</param>
        /// <param name="total">全部数量</param>
        /// <param name="orderNo">订单号</param>
        /// <param name="workOrderNo">工单号</param>
        /// <param name="packBatchNo">打包批次号</param>
        /// <param name="packNo">打包编号</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">截止时间</param>
        /// <param name="inspectStatus">检测状态</param>
        /// <returns>检测列表</returns>
        public List<VInboundInspectInfo> QueryInboundInspectPacks(int page, int limit, out int total, List<string> workshopCodes, string orderNo, string workOrderNo
            , string packBatchNo, string packNo, DateTime startTime, DateTime endTime, PackInboundInspectStatus? inspectStatus)
        {
            if (!workshopCodes.Any())
            {
                total = 0;
                return new List<VInboundInspectInfo>();
            }
            var query = from pack in mesDb.Packs
                        join inspect in mesDb.InboundInspects on pack.PackNo equals inspect.PackNo
                        where workshopCodes.Contains(pack.WorkshopCode) && pack.Valid && pack.PackStatus == PackStatus.Normal && inspect.Valid && inspect.CreateTime >= startTime && inspect.CreateTime < endTime
                        select new VInboundInspectInfo
                        {
                            PkId = inspect.PkId,
                            DutyId = pack.DutyId,
                            MachineId = pack.MachineId,
                            PackBatchNo = pack.PackBatchNo,
                            OrderNo = pack.OrderNo,
                            PackInspectStatus = pack.PackInspectStatus,
                            PackNo = pack.PackNo,
                            PackStatus = pack.PackStatus,
                            WorkOrderNo = pack.WorkOrderNo,
                            WorkshopCode = pack.WorkshopCode,
                            CreateTime = inspect.CreateTime,
                            InspectBy = inspect.InspectBy,
                            InspectTime = inspect.InspectTime,
                            WorkshopName = pack.WorkshopName
                        };
            if (!string.IsNullOrWhiteSpace(orderNo))
            {
                query = query.Where(_ => _.OrderNo.Contains(orderNo));
            }
            if (!string.IsNullOrWhiteSpace(workOrderNo))
            {
                query = query.Where(_ => _.WorkOrderNo.Contains(workOrderNo));
            }
            if (!string.IsNullOrWhiteSpace(packBatchNo))
            {
                query = query.Where(_ => _.PackBatchNo.Contains(packBatchNo));
            }
            if (!string.IsNullOrWhiteSpace(packNo))
            {
                query = query.Where(_ => _.PackNo.Contains(packNo));
            }
            if (inspectStatus.HasValue)
            {
                query = query.Where(_ => _.PackInspectStatus == inspectStatus.Value);
            }

            total = query.Count();

            query = query.OrderByDescending(_ => _.PkId);
            var models = limit <= 0 ? query.ToList() : query.Skip((page - 1) * limit).Take(limit).ToList();

            var userIds = models.Select(_ => _.InspectBy).Where(_ => _ > 0).Distinct().ToList();
            var users = !userIds.Any() ? new List<VUser>() : new UserMgr().QueryUsers(userIds);
            models.ForEach(inspect =>
            {
                inspect.CNInspectBy = users.FirstOrDefault(_ => _.PkId == inspect.InspectBy)?.TrueName;
            });
            return models;
        }

        /// <summary>
        /// 查询打包列表
        /// </summary>
        /// <param name="page">页面索引</param>
        /// <param name="limit">页面容量</param>
        /// <param name="total">全部数量</param>
        /// <param name="orderNo">订单号</param>
        /// <param name="workOrderNo">工单号</param>
        /// <param name="packBatchNo">打包批次号</param>
        /// <param name="packNo">打包编号</param>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">截止日期</param>
        /// <param name="packStatus">打包状态</param>
        /// <param name="inspectStatus">检测状态</param>
        /// <returns>打包列表</returns>
        public List<VPack> QueryPacks(int page, int limit, out int total, List<string> workshopCodes, string orderNo, string workOrderNo, string packBatchNo, string packNo, DateTime startDate, DateTime endDate, PackStatus? packStatus, PackInboundInspectStatus? inspectStatus)
        {
            if (!workshopCodes.Any())
            {
                total = 0;
                return new List<VPack>();
            }
            endDate = endDate.AddDays(1);
            var query = mesDb.Packs.AsNoTracking().Where(_ => workshopCodes.Contains(_.WorkshopCode) && _.Valid && _.CreateTime >= startDate && _.CreateTime < endDate);

            if (!string.IsNullOrWhiteSpace(packNo))
            {
                query = query.Where(_ => _.PackNo.Contains(packNo));
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(workOrderNo))
                {
                    workOrderNo = workOrderNo.Trim();
                    query = query.Where(_ => _.WorkOrderNo == workOrderNo);
                }
                if (!string.IsNullOrWhiteSpace(orderNo))
                {
                    orderNo = orderNo.Trim();
                    query = query.Where(_ => _.OrderNo == orderNo);
                }
                if (!string.IsNullOrWhiteSpace(packBatchNo))
                {
                    packBatchNo = packBatchNo.Trim();
                    query = query.Where(_ => _.PackBatchNo == packBatchNo);
                }
                if (packStatus.HasValue && packStatus.Value > 0)
                {
                    query = query.Where(_ => _.PackStatus == packStatus.Value);
                }
                if (inspectStatus.HasValue)
                {
                    query = query.Where(_ => _.PackInspectStatus == inspectStatus.Value);
                }
            }
            total = query.Count();

            query = query.OrderByDescending(_ => _.PkId);
            var entities = limit <= 0 ? query.ToList() : query.Skip((page - 1) * limit).Take(limit).ToList();

            var userIds = entities.Select(_ => _.CreateBy).Distinct().ToList();
            var users = mesDb.Users.Where(_ => userIds.Contains(_.PkId) && _.Valid).ToList();
            var models = Mapper.Map<List<VPack>>(entities);
            models.ForEach(_ =>
            {
                _.CNCreateBy = users.FirstOrDefault(u => u.PkId == _.CreateBy)?.TrueName;
            });
            return models;
        }

        /// <summary>
        /// 获取打包对象
        /// </summary>
        /// <param name="packNo">包装编号</param>
        /// <returns>打包对象</returns>
        public VPack GetPack(string packNo)
        {
            var entity = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == packNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            var model = Mapper.Map<VPack>(entity);
            if (model != null)
            {
                model.Products = Mapper.Map<List<VPackProduct>>(mesDb.PackProducts.AsNoTracking().Where(_ => _.PackNo == entity.PackNo && _.Valid).OrderBy(_ => _.PkId).ToList());
                model.CNCreateBy = new UserMgr().GetUser(model.CreateBy)?.TrueName;
                model.PackCondition = new PackConditionMgr().GetPackCondition(string.Empty, model.WorkOrderNo, !StringUtils.Equals("Q1", model.QLevel) ? QLevelCondition.NotQ1 : QLevelCondition.Q1);
            }

            return model;
        }

        /// <summary>
        /// 打包
        /// </summary>
        /// <param name="model">打包对象</param>
        /// <param name="barCodes">产品条码</param>
        public VPack CreatePack(VPack model)
        {
            var exist = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            if (exist != null)
            {
                throw new MultiLanBizException(102018);// "当前包装批次号下已有相同的包装编码");
            }

            var machine = mesDb.Machines.AsNoTracking().FirstOrDefault(_ => _.PkId == model.MachineId && _.Valid);
            if (machine == null)
            {
                throw new MultiLanBizException(119003);// "设备不存在或已被删除，无法编辑");
            }

            var duty = new WorkshopDutyMgr().GetCurDuty(model.WorkshopCode);
            if (duty == null)
            {
                throw new MultiLanBizException(110027);//当前时间没有班次在工作
            }

            var packings = mesDb.Packs.AsNoTracking().Where(_ => _.Valid && _.WorkshopCode == model.WorkshopCode && _.PackStatus == PackStatus.Packing).ToList();
            var index = 0;
            while (true)
            {
                index++;
                if (!packings.Any(_ => _.PackIndex == index))
                {
                    break;
                }
            }

            model.PackIndex = index;
            model.WorkshopName = duty.WorkshopName;
            model.MachineName = machine.MachineName;
            model.PackNo = model.PackNo.Trim().ToUpper();
            model.PackBatchNo = model.PackBatchNo.Trim().ToUpper();
            model.DutyId = duty.PkId;
            model.DutyName = duty.DutyName;
            model.CreateTime = DateTime.Now;
            model.PackStatus = PackStatus.Packing;
            model.PackInspectStatus = PackInboundInspectStatus.UnInspected;

            var entity = Mapper.Map<Pack>(model);
            mesDb.Packs.Add(entity);
            mesDb.SaveChanges();

            return Mapper.Map<VPack>(entity);
        }

        /// <summary>
        /// 解包
        /// </summary>
        /// <param name="model">包装对象</param>
        public void UnPack(VPack model)
        {
            var entity = mesDb.Packs.FirstOrDefault(_ => _.PackNo == model.PackNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            if (entity == null)
            {
                throw new MultiLanBizException(102008);// "包装不存在");
            }
            else if (!string.IsNullOrWhiteSpace(entity.CabinetNo))
            {
                throw new MultiLanBizException(102019, entity.CabinetNo);// 该箱组件已被拼柜，请解柜后重试，柜号为：
            }

            entity.PackInspectStatus = PackInboundInspectStatus.CancelInspect;
            entity.PackStatus = PackStatus.Unpack;
            entity.UnpackTime = DateTime.Now;
            entity.ModifyBy = model.ModifyBy;
            entity.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    #region 处理组件
                    var components = mesDb.Components.AsNoTracking().Where(_ => _.PackNo == entity.PackNo && _.Valid).ToList();
                    var user = new UserMgr().QueryUsers(new List<int> { model.ModifyBy }).FirstOrDefault();
                    var logs = components.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.BarCode,
                        LogName = "组件解包",
                        LogStatus = "异常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"组件解包，原包装号：{_.PackNo}，原打包时间：{_.PackTime?.ToString("yyyy-MM-dd HH:mm:ss")}",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.PackBatchNo = "";
                        _.PackNo = "";
                        //_.PackTime = null;
                        _.ModifyBy = entity.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    var packProducts = mesDb.PackProducts.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Valid).ToList();
                    packProducts.ForEach(_ =>
                    {
                        mesDb.PackProducts.Attach(_);
                        _.Valid = false;
                        _.ModifyBy = entity.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    #endregion

                    #region 处理入库检
                    var inspects = mesDb.InboundInspects.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Status != PackInboundInspectStatus.CancelInspect && _.Valid).ToList();
                    foreach (var inspect in inspects)
                    {
                        mesDb.InboundInspects.Attach(inspect);
                        //未检测时，删除检测任务
                        if (inspect.Status == PackInboundInspectStatus.UnInspected)
                        {
                            inspect.Valid = false;
                        }
                        else
                        {
                            inspect.Status = PackInboundInspectStatus.CancelInspect;
                        }
                        inspect.ModifyBy = entity.ModifyBy;
                        inspect.ModifyTime = DateTime.Now;

                        var products = mesDb.InboundInspectProducts.AsNoTracking().Where(_ => _.InspectId == inspect.PkId && _.Valid).ToList();
                        products.ForEach(_ =>
                        {
                            mesDb.InboundInspectProducts.Attach(_);
                            _.Valid = false;
                            _.ModifyBy = entity.ModifyBy;
                            _.ModifyTime = DateTime.Now;
                        });
                    }
                    mesDb.SaveChanges();
                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"解包异常，箱号：{model.PackNo}，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 查询工单过站BOM列表
        /// </summary>
        /// <param name="workOrderNo">工单号</param>
        /// <param name="siteType">站点</param>
        /// <returns>BOM列表</returns>
        public List<VWorkOrderSiteBom> QueryWorkOrderSiteBoms(string workOrderNo, SiteType siteType)
        {
            //var bomEntities = mesDb.WorkOrderBoms.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).ToList();
            //var siteBoms = mesDb.ProductSiteBoms.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).ToList();
            //var enableBoms = bomEntities.Where(_ => !siteBoms.Where(b => b.SiteType != siteType).Select(b => b.BomProductCode).Contains(_.ProductCode)).Select(_ => new VWorkOrderSiteBom
            //{
            //    BomProductCode = _.ProductCode,
            //    BomProductName = _.ProductName,
            //    BomCount = _.Count,
            //    Selected = siteBoms.Any(s => s.SiteType == siteType && s.BomProductCode == _.ProductCode)
            //}).OrderBy(_ => _.BomProductName).ToList();

            return new List<VWorkOrderSiteBom>(); ;
        }

        /// <summary>
        /// 查询工单过站BOM列表
        /// </summary>
        /// <param name="workOrderNo">工单号</param>
        /// <param name="siteType">站点</param>
        /// <returns>BOM列表</returns>
        public List<VWorkOrderBom> QueryWorkOrderBoms(string workOrderNo)
        {
            var bomEntities = mesDb.WorkOrderBoms.Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).ToList();

            return Mapper.Map<List<VWorkOrderBom>>(bomEntities);
        }

        /// <summary>
        /// 查询分片任务
        /// </summary>
        /// <param name="workOrderNo">工单号</param>
        /// <returns>任务列表</returns>
        public List<VDistributeTaskInfo> QueryWorkOrderDistributeTasks(string workOrderNo)
        {
            var entites = mesDb.DistributeTasks.Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).Select(_ => new VDistributeTaskInfo
            {
                MachineId = _.MachineId,
                CellColor = _.CellColor,
                CellBoxNo = _.CellBoxNo,
                CodeCount = _.CodeCount,
                CreateBy = _.CreateBy,
                CreateTime = _.CreateTime,
                PkId = _.PkId
            }).ToList();

            var machineIds = entites.Select(_ => _.MachineId).Distinct().ToList();
            var machines = mesDb.Machines.Where(_ => machineIds.Contains(_.PkId) && _.Valid).ToList();
            var userIds = entites.Select(_ => _.CreateBy).Distinct().ToList();
            var users = new UserMgr().QueryUsers(userIds);
            entites.ForEach(info =>
            {
                info.CNCreateBy = users.FirstOrDefault(_ => _.PkId == info.CreateBy)?.TrueName;
                info.MachineName = machines.FirstOrDefault(_ => _.PkId == info.MachineId)?.MachineName;
            });
            return entites;
        }

        /// <summary>
        /// 获取工单标片
        /// </summary>
        /// <param name="workOrderId">工单ID</param>
        /// <returns>标片对象</returns>
        public VStandardPiece GetStandardPiece(string orderNo, string workOrderNo)
        {
            StandardPiece entity = null;
            if (!string.IsNullOrWhiteSpace(workOrderNo))
            {
                entity = (from piece in mesDb.StandardPieces.AsNoTracking()
                          join workOrderPiece in mesDb.WorkOrderStandardPieces.AsNoTracking() on piece.PkId equals workOrderPiece.StandardPieceId
                          where workOrderPiece.WorkOrderNo == workOrderNo && workOrderPiece.OrderNo == "" && piece.Valid && workOrderPiece.Valid
                          select piece).FirstOrDefault();
                if (entity == null)
                {
                    var workOrder = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == workOrderNo && _.Valid);
                    if (workOrder == null)
                    {
                        throw new MultiLanBizException(111002);//工单不存在
                    }
                    entity = (from piece in mesDb.StandardPieces.AsNoTracking()
                              join workOrderPiece in mesDb.WorkOrderStandardPieces.AsNoTracking() on piece.PkId equals workOrderPiece.StandardPieceId
                              where workOrderPiece.WorkOrderNo == "" && workOrderPiece.OrderNo == workOrder.OrderNo && piece.Valid && workOrderPiece.Valid
                              select piece).FirstOrDefault();
                }
            }
            else
            {
                entity = (from piece in mesDb.StandardPieces.AsNoTracking()
                          join workOrderPiece in mesDb.WorkOrderStandardPieces.AsNoTracking() on piece.PkId equals workOrderPiece.StandardPieceId
                          where workOrderPiece.WorkOrderNo == "" && workOrderPiece.OrderNo == orderNo && piece.Valid && workOrderPiece.Valid
                          select piece).FirstOrDefault();
            }

            return Mapper.Map<VStandardPiece>(entity);
        }

        /// <summary>
        /// 获取工单标片
        /// </summary>
        /// <param name="workOrderId">工单ID</param>
        /// <returns>标片对象</returns>
        public List<VWorkOrderStandardPieceInfo> QueryWorkOrderStandardPieces(string orderNo, string workOrderNo)
        {
            List<WorkOrderStandardPiece> entities = new List<WorkOrderStandardPiece>();
            if (!string.IsNullOrWhiteSpace(workOrderNo))
            {
                var workOrder = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == workOrderNo && _.Valid);
                if (workOrder == null)
                {
                    return new List<VWorkOrderStandardPieceInfo>();
                }

                entities.AddRange(mesDb.WorkOrderStandardPieces.AsNoTracking().Where(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.Valid).ToList());
                if (!entities.Any())
                {
                    entities.AddRange(mesDb.WorkOrderStandardPieces.AsNoTracking().Where(_ => _.OrderNo == workOrder.OrderNo && _.WorkOrderNo == "" && _.Valid).ToList());
                }
            }
            else if (!string.IsNullOrWhiteSpace(orderNo))
            {
                entities.AddRange(mesDb.WorkOrderStandardPieces.AsNoTracking().Where(_ => _.OrderNo == orderNo && _.WorkOrderNo == "" && _.Valid).ToList());
            }
            if (!entities.Any())
            {
                return new List<VWorkOrderStandardPieceInfo>();
            }

            var barCodes = entities.Select(_ => _.ProductCode).ToList();
            var pieces = mesDb.StandardPieces.AsNoTracking().Where(_ => barCodes.Contains(_.ProductCode) && _.Valid).ToList();

            var result = entities.Select(entity =>
            {
                var piece = pieces.FirstOrDefault(_ => string.Equals(_.ProductCode, entity.ProductCode, StringComparison.CurrentCultureIgnoreCase));
                if (piece == null)
                {
                    return null;
                }
                var model = new VWorkOrderStandardPieceInfo
                {
                    WorkOrderNo = entity.WorkOrderNo,
                    OrderNo = entity.OrderNo,
                    Model = piece.Model,
                    Frequency = entity.Frequency,
                    EndDate = piece.EndDate,
                    ProductCode = piece.ProductCode,
                    Pmax = piece.Pmax,
                    PmaxToleranceDown = piece.PmaxToleranceDown,
                    PmaxToleranceUp = piece.PmaxToleranceUp,
                    Vmp = piece.Vmp,
                    VmpToleranceDown = piece.VmpToleranceDown,
                    VmpToleranceUp = piece.VmpToleranceUp,
                    FF = piece.FF,
                    FFToleranceDown = piece.FFToleranceDown,
                    FFToleranceUp = piece.FFToleranceUp,
                    Imp = piece.Imp,
                    ImpToleranceDown = piece.ImpToleranceDown,
                    ImpToleranceUp = piece.ImpToleranceUp,
                    Isc = piece.Isc,
                    IscToleranceDown = piece.IscToleranceDown,
                    IscToleranceUp = piece.IscToleranceUp,
                    StartDate = piece.StartDate,
                    Status = piece.Status,
                    Voc = piece.Voc,
                    VocToleranceDown = piece.VocToleranceDown,
                    VocToleranceUp = piece.VocToleranceUp
                };

                return model;
            }).ToList();

            return result.Where(_ => _ != null).ToList();
        }

        /// <summary>
        /// 保存工单标片
        /// </summary>
        /// <param name="model">标片对象</param>
        public void SaveStandardPiece(string orderNo, string workOrderNo, List<string> productCodes, decimal? frequency, int @operator)
        {
            var pieces = mesDb.StandardPieces.AsNoTracking().Where(_ => productCodes.Contains(_.ProductCode) && _.Valid).ToList();
            if (pieces.Any(piece => piece.Status == CommonStatus.Disabled))
            {
                throw new MultiLanBizException(102021, string.Join("、", pieces.Where(piece => piece.Status == CommonStatus.Disabled).Select(_ => _.ProductCode)));// "标片状态不可用");
            }

            var models = pieces.Select(_ => new WorkOrderStandardPiece
            {
                WorkOrderNo = workOrderNo,
                OrderNo = orderNo,
                StandardPieceId = _.PkId,
                ProductCode = _.ProductCode,
                Model = _.Model,
                Frequency = frequency,
                CreateBy = @operator,
                ModifyBy = @operator,
                CreateTime = DateTime.Now
            }).ToList();

            var entities = !string.IsNullOrWhiteSpace(workOrderNo) ? mesDb.WorkOrderStandardPieces.AsNoTracking().Where(_ => _.WorkOrderNo == workOrderNo && _.Valid).ToList()
               : mesDb.WorkOrderStandardPieces.AsNoTracking().Where(_ => _.OrderNo == orderNo && _.WorkOrderNo == "" && _.Valid).ToList();

            var newPieces = models.Where(model => !entities.Any(_ => string.Equals(_.ProductCode, model.ProductCode, StringComparison.CurrentCultureIgnoreCase))).ToList();
            mesDb.WorkOrderStandardPieces.AddRange(newPieces);

            foreach (var entity in entities)
            {
                mesDb.WorkOrderStandardPieces.Attach(entity);

                var model = models.FirstOrDefault(_ => string.Equals(_.ProductCode, entity.ProductCode, StringComparison.CurrentCultureIgnoreCase));
                if (model == null)
                {
                    entity.Valid = false;
                    entity.ModifyBy = @operator;
                    entity.ModifyTime = DateTime.Now;
                }
                else
                {
                    entity.Model = model.Model;
                    entity.Frequency = model.Frequency;
                    entity.ModifyBy = @operator;
                    entity.ModifyTime = DateTime.Now;
                }
            }

            mesDb.SaveChanges();
        }

        /// <summary>
        /// 分片
        /// </summary>
        /// <param name="model">分片任务</param>
        /// <param name="codes">多个条码</param>
        public void Distribute(VDistributeTask model, List<string> codes)
        {
            var workOrder = GetWorkOrder(model.WorkOrderNo);
            if (workOrder == null)
            {
                throw new MultiLanBizException(102022, model.WorkOrderNo);// $"工单不存在：{model.WorkOrderNo}");
            }
            var workOrderPiece = new WorkOrderMgr().GetStandardPiece("", model.WorkOrderNo);
            if (workOrderPiece == null)
            {
                throw new MultiLanBizException(102027);//当前工单尚未绑定标片，无法分片
            }
            var workOrderBinningSchema = new BinningSchemeMgr().GetWorkorderBinningSchema(workOrder.OrderNo, workOrder.WorkOrderNo);
            if (workOrderBinningSchema == null)
            {
                throw new MultiLanBizException(102028);//当前工单尚未绑定分档规则，无法分片
            }
            var workOrderLabel = new LabelMgr().GetWorkOrderLabel(workOrder.OrderNo, workOrder.WorkOrderNo);
            if (workOrderLabel == null)
            {
                throw new MultiLanBizException(102029);//当前工单尚未上传标签，无法分片
            }
            var workOrderColorMatches = new LevelColorMgr().QueryColorMatches(workOrder.OrderNo, workOrder.WorkOrderNo);
            if (!workOrderColorMatches.Any())
            {
                throw new MultiLanBizException(102030);//当前工单尚未绑定电池片和组件颜色，无法分片
            }
            var color = mesDb.ColorSets.AsNoTracking().FirstOrDefault(_ => _.ColorType == ColorType.CellColor && _.ColorCode == model.CellColor && _.Valid);
            if (color == null)
            {
                throw new MultiLanBizException(102025);// 电池片颜色不存在
            }
            var colorMatch = mesDb.ColorMatches.AsNoTracking().FirstOrDefault(_ => _.OrderNo == workOrder.OrderNo && _.CellColorCode == color.ColorCode && _.Valid);
            if (colorMatch == null)
            {
                throw new MultiLanBizException(102026);// 当前电池片颜色未匹配成品组件颜色
            }
            var config = new ViaSiteConfigMgr().GetConfig(workOrder.OrderNo, workOrder.WorkOrderNo);
            if (config?.ConfigModel?.MaterialInfoControl == true)
            {
                var workOrderAllocateOrderNos = mesDb.AllocateOrders.AsNoTracking().Where(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.Valid).Select(_ => _.AllocateNo).ToList();
                var workOrderAllocateProducts = !workOrderAllocateOrderNos.Any() ? new List<AllocateProduct>()
                    : mesDb.AllocateProducts.AsNoTracking().Where(_ => workOrderAllocateOrderNos.Contains(_.AllocateNo) && _.Valid).ToList();
                if (!workOrderAllocateOrderNos.Any())
                {
                    throw new MultiLanBizException(102035, workOrder.WorkOrderNo);//当前工单没有调拨单，缺少物料信息无法生产，工单号为：
                }

                var workOrderBoms = mesDb.WorkOrderBoms.AsNoTracking().Where(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.Valid).ToList();
                var categoryNames = new List<string> { "电池片", "玻璃", "背板", "EVA", "边框", "接线盒", "焊带" };
                var mainBomCategories = workOrderBoms.Where(_ => categoryNames.Contains(_.CategoryName, StringComparer.CurrentCultureIgnoreCase))
                    .Select(_ => _.CategoryName).Distinct().ToList();

                var errMsgs = new List<string>();
                foreach (var category in mainBomCategories)
                {
                    var allocateProducts = workOrderAllocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, category)).ToList();
                    if (!allocateProducts.Any(_ => !string.IsNullOrWhiteSpace(_.ProductionCompany)))
                    {
                        errMsgs.Add($"{category}厂家");
                    }
                    if (!allocateProducts.Any(_ => !string.IsNullOrWhiteSpace(_.Specifications)))
                    {
                        errMsgs.Add($"{category}规格");
                    }
                }

                if (errMsgs.Any())
                {
                    throw new MultiLanBizException(102035, $"{workOrder.WorkOrderNo}，{string.Join("、", errMsgs)}");//当前工单缺少物料信息，工单号和物料信息为：
                }
            }

            var codeEntities = new List<DistributeCode>();
            if (model.DistributeType == DistributeType.Single)
            {
                codeEntities.Add(new DistributeCode
                {
                    WorkOrderNo = workOrder.WorkOrderNo,
                    OrderNo = workOrder.OrderNo,
                    Code = model.SingleCode,
                    CreateTime = DateTime.Now,
                    Status = DistributeCodeStatus.UnPrinted
                });
            }
            else if (model.DistributeType == DistributeType.Multiple)
            {
                codes = codes ?? new List<string>();
                codeEntities.AddRange(codes.Select(_ => new DistributeCode
                {
                    WorkOrderNo = workOrder.WorkOrderNo,
                    OrderNo = workOrder.OrderNo,
                    Code = _,
                    CreateTime = DateTime.Now,
                    Status = DistributeCodeStatus.UnPrinted
                }));
            }
            else
            {
                var format = "";
                for (int i = 0; i < model.SerialNumCount; i++)
                {
                    format = format + "0";
                }
                for (int i = model.StartNum.Value; i <= model.EndNum.Value; i++)
                {
                    codeEntities.Add(new DistributeCode
                    {
                        WorkOrderNo = workOrder.WorkOrderNo,
                        OrderNo = workOrder.OrderNo,
                        Code = $"{model.CodeFront}{i.ToString(format)}{model.CodeEnd}",
                        CreateTime = DateTime.Now,
                        Status = DistributeCodeStatus.UnPrinted
                    });
                }
            }
            var curCodes = codeEntities.Select(_ => _.Code.Trim().ToUpper().Trim()).Distinct().ToList();
            if (curCodes.Count > 2000)
            {
                throw new MultiLanBizException(102037);//每次最多可分片组件2000块
            }

            var components = mesDb.Components.AsNoTracking().Where(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.Valid).ToList();

            var existCodes = curCodes.Where(_ => components.Where(c => c.DistributeTime.HasValue).Select(c => c.BarCode.Trim().ToUpper()).Contains(_.Trim().ToUpper())).ToList();
            var inValidCodes = curCodes.Where(_ => !components.Select(c => c.BarCode.Trim().ToUpper()).Contains(_.Trim().ToUpper())).ToList();
            if (existCodes.Any())
            {
                throw new MultiLanBizException(102023, string.Join("、", existCodes.Select(_ => _)));// $"下列条码已被分片：{string.Join("、", existCodes.Select(_ => _.Code))}");
            }
            else if (inValidCodes.Any())
            {
                throw new MultiLanBizException(102024, string.Join("、", inValidCodes.Select(_ => _)));// $"下列条码不存在：{string.Join("、", existCodes.Select(_ => _.Code))}");
            }

            model.WorkshopCode = workOrder.WorkshopCode;
            model.WorkshopName = workOrder.WorkshopName;
            model.CreateTime = DateTime.Now;
            model.CodeCount = model.DistributeType == DistributeType.Single ? 1 : (model.DistributeType == DistributeType.Multiple ? codes.Count : (model.EndNum.Value - model.StartNum.Value + 1));
            model.CellColorCode = color.ColorCode;
            model.CellColor = color.Color;
            var entity = Mapper.Map<DistributeTask>(model);
            mesDb.DistributeTasks.Add(entity);
            mesDb.SaveChanges();

            var machine = new MachineMgr().GetMachine(model.MachineId);
            codeEntities.ForEach(_ =>
            {
                _.Code = _.Code.Trim().ToUpper();
                _.LineId = machine?.LineId ?? 0;
                _.LineName = machine?.LineName;
                _.WorkshopCode = workOrder.WorkshopCode;
                _.WorkshopName = workOrder.WorkshopName;
                _.ProductCode = workOrder.ProductCode;
                _.ProductName = workOrder.ProductName;
                _.DistributeTaskId = entity.PkId;
            });
            mesDb.DistributeCodes.AddRange(codeEntities);
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                try
                {
                    var produceComponents = components.Where(_ => curCodes.Contains(_.BarCode)).ToList();
                    produceComponents.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.CellArea = model.CellArea;
                        _.CellEfficiency = model.CellEfficiency;
                        _.SinglePiecePower = Convert.ToDecimal((model.CellEfficiency * model.CellArea / 1000).ToString("0.0000"));
                        _.TheoreticalPower = _.SinglePiecePower * (workOrder.CellQuantity ?? 0);
                        _.ProduceStatus = ProduceStatus.InProduction;
                        _.ProductStatus = ProductStatus.Normal;
                        _.DistributeTime = DateTime.Now;
                        _.LastSiteTime = DateTime.Now;
                        _.CellColor = colorMatch.CellColor;
                        _.CellBoxNo = model.CellBoxNo;
                        _.ComponentColor = colorMatch.ComponentColor;
                        _.ModifyBy = model.CreateBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.SaveChanges();

                    var user = new UserMgr().QueryUsers(new List<int> { model.CreateBy }).FirstOrDefault();
                    var logs = codeEntities.Select(_ => new VOprLog
                    {
                        SubjectType = "组件",
                        SubjectNo = _.Code,
                        LogName = "分片",
                        LogStatus = "正常",
                        OpeatorId = model.CreateBy,
                        OpeatorName = user?.TrueName,
                        LogContent = $"组件分片：{_.Code}，本次共分片{codeEntities.Count}个",
                        LogTime = DateTime.Now,
                        CreateBy = model.CreateBy
                    }).ToList();
                    new OprLogMgr().AddLogs(logs);
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"分片异常，异常信息：{ex.Message}");
                }
            });
        }

        /// <summary>
        /// 获取检核产品
        /// </summary>
        /// <param name="inspectId">检核ID</param>
        /// <returns>产品列表</returns>
        public List<VInboundInspectProduct> QueryInspectProducts(int inspectId)
        {
            var entities = mesDb.InboundInspectProducts.AsNoTracking().Where(_ => _.InspectId == inspectId && _.Valid == true).ToList();
            return Mapper.Map<List<VInboundInspectProduct>>(entities);
        }

        /// <summary>
        /// 保存入库检核
        /// </summary>
        /// <param name="model">入库检核对象</param>
        public void Verification(VInboundInspect model)
        {
            var entity = mesDb.InboundInspects.AsNoTracking().FirstOrDefault(_ => _.Valid && _.PkId == model.PkId);
            if (entity == null)
            {
                throw new MultiLanBizException(102039, model.PackNo);//当前入库检不存在
            }
            else if (entity.Status != PackInboundInspectStatus.UnInspected)
            {
                throw new MultiLanBizException(102043, EnumConvert.ToDesc(entity.Status));//当前状态无法执行入库检
            }

            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == entity.PackNo && _.PackStatus == PackStatus.Normal && _.Valid);
            if (pack == null)
            {
                throw new MultiLanBizException(102008, model.PackNo);//包装不存在
            }

            mesDb.Packs.Attach(pack);
            pack.PackInspectStatus = model.Status;
            pack.ModifyBy = model.InspectBy;
            pack.ModifyTime = DateTime.Now;

            var inspectProducts = mesDb.InboundInspectProducts.AsNoTracking().Where(_ => _.InspectId == model.PkId && _.Valid == true).ToList();
            foreach (var item in inspectProducts)
            {
                var product = model.Products.FirstOrDefault(_ => _.PkId == item.PkId && _.Valid == true);
                if (product != null)
                {
                    mesDb.InboundInspectProducts.Attach(item);
                    item.Status = product.Status;
                    item.ModifyBy = model.ModifyBy;
                    item.ModifyTime = DateTime.Now;
                }
            }

            mesDb.InboundInspects.Attach(entity);
            entity.InspectBy = model.InspectBy;
            entity.InspectTime = DateTime.Now;
            entity.RefuseReason = model.RefuseReason;
            entity.Status = model.Status;
            entity.ModifyBy = model.ModifyBy;
            entity.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                var barCodes = inspectProducts.Select(_ => _.BarCode.ToUpper().Trim()).Distinct().ToList();
                if (model.Status == PackInboundInspectStatus.Inspected)
                {
                    var components = mesDb.Components.AsNoTracking().Where(_ => barCodes.Contains(_.BarCode) && _.Valid).ToList();
                    components.ForEach(_ =>
                    {
                        mesDb.Components.Attach(_);
                        _.InboundInspectTime = DateTime.Now;
                        _.ModifyBy = model.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    mesDb.SaveChanges();
                }

                var user = new UserMgr().QueryUsers(new List<int> { model.ModifyBy }).FirstOrDefault();
                var logs = barCodes.Select(_ => new VOprLog
                {
                    SubjectType = "组件",
                    SubjectNo = _,
                    LogName = "入库检",
                    LogStatus = model.Status == PackInboundInspectStatus.Inspected ? "正常" : "异常",
                    OpeatorId = model.ModifyBy,
                    OpeatorName = user?.TrueName,
                    LogContent = $"入库检结果：{model.CNStatus}，本次共检测{barCodes.Count}个",
                    LogTime = DateTime.Now,
                    CreateBy = model.CreateBy
                }).ToList();
                new OprLogMgr().AddLogs(logs);

                //入库检成功，ERP入库
                if (model.Status == PackInboundInspectStatus.Inspected)
                {
                    entity.ErpTaskExcuted = true;
                    mesDb.SaveChanges();
                }
            });
        }

        /// <summary>
        /// 查询包装的IV数据
        /// </summary>
        /// <param name="packNo">打包编号</param>
        /// <returns>IV数据列表</returns>
        public List<VProductViaSiteIVData> QueryPackIvDatas(string packNo)
        {
            var packProducts = mesDb.PackProducts.AsNoTracking().Where(_ => _.PackNo == packNo && _.Valid).OrderBy(_ => _.CreateTime).ToList();
            var barCodes = packProducts.Select(_ => _.BarCode.ToUpper().Trim()).Distinct().ToList();
            var ivDatas = mesDb.ProductViaSiteIVDatas.AsNoTracking().Where(_ => barCodes.Contains(_.BarCode) && _.Valid).ToList();
            var models = packProducts.Select(item =>
            {
                var ivData = ivDatas.Where(_ => StringUtils.Equals(_.BarCode, item.BarCode)).OrderByDescending(_ => _.PkId).FirstOrDefault();
                return ivData != null ? Mapper.Map<VProductViaSiteIVData>(ivData) : new VProductViaSiteIVData
                {
                    BarCode = item.BarCode.ToUpper().Trim()
                };
            }).ToList();
            return models;
        }

        /// <summary>
        /// 获取打印数据
        /// </summary>
        /// <param name="taskId">任务ID</param>
        /// <returns>打印列表</returns>
        public List<VDistributeCode> QueryPrintCodes(int taskId)
        {
            var task = mesDb.DistributeCodeOperateTasks.AsNoTracking().FirstOrDefault(_ => _.PkId == taskId && _.Valid);
            if (task == null)
            {
                return new List<VDistributeCode>();
            }

            var codes = mesDb.DistributeCodeOperates.Where(_ => _.TaskId == task.PkId && _.Valid).OrderBy(_ => _.Code).ToList();

            return codes.Select(_ => new VDistributeCode { Code = _.Code, PkId = _.CodeId }).ToList();
        }

        /// <summary>
        /// ERP工单同步
        /// </summary>
        /// <param name="model">工单对象</param>
        public void AsyncWorkOrder(List<VWorkOrder> models)
        {
            var productInfos = mesDb.Products.AsNoTracking().Where(_ => _.Valid).ToList();
            var categories = mesDb.ProductCategories.AsNoTracking().Where(_ => _.Valid).ToList();
            var workshops = mesDb.Workshops.AsNoTracking().Where(_ => _.Valid).ToList();
            models.ForEach(model =>
            {
                model.WorkOrderTime = DateTime.Now;
                model.WorkshopName = workshops.FirstOrDefault(_ => string.Equals(_.WorkshopCode, model.WorkshopCode, StringComparison.CurrentCultureIgnoreCase))?.WorkshopName;
                if (!string.IsNullOrWhiteSpace(model.ProductCode))
                {
                    var product = productInfos.FirstOrDefault(_ => string.Equals(model.ProductCode, _.ProductCode, StringComparison.CurrentCultureIgnoreCase));
                    if (product == null)
                    {
                        throw new BizException(1, $"工单成品料号对应的基准物料不存在：{model.WorkOrderNo}，{model.ProductCode}");
                    }
                    model.ProductName = product.ProductName;
                    model.ProductSpecs = product.Specifications;
                }
            });
            models = models.Where(_ => !string.IsNullOrWhiteSpace(_.ProductName)).ToList();

            foreach (var item in models)
            {
                try
                {
                    var entity = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == item.WorkOrderNo && _.Valid);
                    if (entity == null)
                    {
                        entity = Mapper.Map<WorkOrder>(item);
                        entity.CreateTime = DateTime.Now;
                        entity.ModifyBy = 0;
                        entity.ModifyTime = null;
                        mesDb.WorkOrders.Add(entity);

                        var order = mesDb.Orders.AsNoTracking().FirstOrDefault(_ => _.InnerOrderNo == entity.OrderNo && _.Valid);
                        if (order == null)
                        {
                            order = new Order
                            {
                                InnerOrderNo = entity.OrderNo,
                                Status = OrderStatus.New,
                                Breaked = false,
                                CreateTime = DateTime.Now,
                                OrderTime = DateTime.Now,
                                ReviewTime = DateTime.Now
                            };
                            mesDb.Orders.Add(order);
                            mesDb.SaveChanges();
                        }
                    }
                    else
                    {
                        var sqlParams = new List<SqlParameter>();
                        var oldParams = new List<SqlParameter>();
                        if (!string.Equals(entity.WorkshopCode, item.WorkshopCode, StringComparison.CurrentCultureIgnoreCase))
                        {
                            sqlParams.Add(new SqlParameter("WorkshopCode", item.WorkshopCode));
                            sqlParams.Add(new SqlParameter("WorkshopName", item.WorkshopName));

                            oldParams.Add(new SqlParameter("WorkshopCode", entity.WorkshopCode));
                            oldParams.Add(new SqlParameter("WorkshopName", entity.WorkshopName));
                        }
                        if (!string.Equals(entity.OrderNo, item.OrderNo, StringComparison.CurrentCultureIgnoreCase))
                        {
                            sqlParams.Add(new SqlParameter("OrderNo", item.OrderNo));
                            oldParams.Add(new SqlParameter("OrderNo", entity.OrderNo));
                        }
                        if (!string.Equals(entity.ProductCode, item.ProductCode, StringComparison.CurrentCultureIgnoreCase))
                        {
                            sqlParams.Add(new SqlParameter("ProductCode", item.ProductCode));
                            oldParams.Add(new SqlParameter("OrderNo", entity.OrderNo));
                        }
                        if (!string.Equals(entity.ProductName, item.ProductName, StringComparison.CurrentCultureIgnoreCase))
                        {
                            sqlParams.Add(new SqlParameter("ProductName", item.ProductName));
                            oldParams.Add(new SqlParameter("OrderNo", entity.OrderNo));
                        }
                        if (!string.Equals(entity.ProductSpecs, item.ProductSpecs, StringComparison.CurrentCultureIgnoreCase))
                        {
                            sqlParams.Add(new SqlParameter("ProductSpecs", item.ProductSpecs));
                            oldParams.Add(new SqlParameter("OrderNo", entity.OrderNo));
                        }
                        if (sqlParams.Any())
                        {
                            logger.Warn($"工单数据修改，工单号：{item.WorkOrderNo}，老数据：{string.Join(", ", oldParams.Select(_ => $"{_.ParameterName} = {_.Value}"))}，新数据：{string.Join(", ", sqlParams.Select(_ => $"{_.ParameterName} = {_.Value}"))}");

                            var setSql = string.Join(", ", sqlParams.Select(_ => $"{_.ParameterName} = @{_.ParameterName}"));
                            sqlParams.Add(new SqlParameter("WorkOrderNo", entity.WorkOrderNo));

                            mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET {setSql} WHERE WorkOrderNo = @WorkOrderNo AND Valid = 1;", sqlParams.ToArray());
                            mesDb.Database.ExecuteSqlCommand($"UPDATE Pack SET {setSql} WHERE WorkOrderNo = @WorkOrderNo AND PackStatus <> 2 AND Valid = 1;", sqlParams.ToArray());

                            if (sqlParams.Any(_ => string.Equals(_.ParameterName, "WorkshopCode", StringComparison.CurrentCultureIgnoreCase)))
                            {
                                sqlParams.Remove(sqlParams.FirstOrDefault(_ => string.Equals(_.ParameterName, "WorkshopCode", StringComparison.CurrentCultureIgnoreCase)));
                                sqlParams.Remove(sqlParams.FirstOrDefault(_ => string.Equals(_.ParameterName, "WorkshopName", StringComparison.CurrentCultureIgnoreCase)));
                            }

                            sqlParams.Remove(sqlParams.FirstOrDefault(_ => string.Equals(_.ParameterName, "WorkOrderNo", StringComparison.CurrentCultureIgnoreCase)));
                            if (sqlParams.Any())
                            {
                                setSql = string.Join(", ", sqlParams.Select(_ => $"{_.ParameterName} = @{_.ParameterName}"));
                                sqlParams.Add(new SqlParameter("WorkOrderNo", entity.WorkOrderNo));
                                mesDb.Database.ExecuteSqlCommand($"UPDATE Cabinet SET {setSql} WHERE WorkOrderNo = @WorkOrderNo AND [Status] <> 2 AND Valid = 1;", sqlParams.ToArray());
                            }
                        }

                        var order = mesDb.Orders.AsNoTracking().FirstOrDefault(_ => _.InnerOrderNo == item.OrderNo && _.Valid);
                        if (order == null)
                        {
                            order = new Order
                            {
                                InnerOrderNo = entity.OrderNo,
                                Status = OrderStatus.New,
                                Breaked = false,
                                CreateTime = DateTime.Now,
                                OrderTime = DateTime.Now,
                                ReviewTime = DateTime.Now
                            };
                            mesDb.Orders.Add(order);
                        }

                        if (!StringUtils.Equals(item.OrderNo, entity.OrderNo))
                        {
                            var orderWorkOrders = mesDb.WorkOrders.AsNoTracking().Count(_ => _.OrderNo == entity.OrderNo && _.WorkOrderNo != entity.WorkOrderNo && _.Valid);
                            if (orderWorkOrders <= 0)
                            {
                                var delOrder = mesDb.Orders.AsNoTracking().FirstOrDefault(_ => _.InnerOrderNo == entity.OrderNo && _.Valid);
                                if (delOrder != null)
                                {
                                    mesDb.Orders.Attach(delOrder);
                                    delOrder.Valid = false;
                                    delOrder.ModifyBy = item.ModifyBy;
                                    delOrder.ModifyTime = DateTime.Now;
                                }
                            }
                        }

                        mesDb.WorkOrders.Attach(entity);
                        entity.GlassType = item.GlassType;
                        entity.ContractNo = item.ContractNo;
                        entity.ProjectName = item.ProjectName;
                        entity.ProtocolNo = item.ProtocolNo;
                        entity.AssistUnitCode = item.AssistUnitCode;
                        entity.StartDate = item.StartDate;
                        entity.EndDate = item.EndDate;
                        entity.Count = item.Count;
                        entity.WorkshopCode = item.WorkshopCode;
                        entity.WorkshopName = item.WorkshopName;
                        entity.OrderNo = item.OrderNo;
                        entity.InnerOrderNo = item.InnerOrderNo;
                        entity.ProductCode = item.ProductCode;
                        entity.ProductName = item.ProductName;
                        entity.ProductSpecs = item.ProductSpecs;
                        entity.ModifyBy = item.ModifyBy;
                        entity.ModifyTime = DateTime.Now;
                    }
                    mesDb.SaveChanges();

                    #region 根据全局配置生成订单配置
                    new ViaSiteConfigMgr().ResetOrderConfig(new VViaSiteConfig { OrderNo = entity.OrderNo, WorkOrderNo = entity.WorkOrderNo });
                    #endregion

                    #region 处理工单BOM
                    var boms = item.Boms.Select(_ => new WorkOrderBom
                    {
                        WorkOrderNo = entity.WorkOrderNo,
                        ProductCode = _.ProductCode,
                        Count = _.Count,
                        ProductCompany = _.ProductCompany,
                        Unit = _.Unit,
                        SingleCount = _.SingleCount,
                        CreateTime = DateTime.Now
                    }).ToList();
                    foreach (var bom in boms)
                    {
                        var productInfo = productInfos.FirstOrDefault(_ => string.Equals(_.ProductCode, bom.ProductCode, StringComparison.CurrentCultureIgnoreCase));
                        if (productInfo == null)
                        {
                            logger.Error($"物料编码不存在，工单号：{bom.WorkOrderNo}，料号：{bom.ProductCode}");
                            continue;
                        }
                        bom.ProductName = productInfo.ProductName;
                        bom.Specifications = productInfo.Specifications;
                        var category = AllocateOrderMgr.GetProductMainCategory(productInfo, categories);
                        bom.CategoryCode = category?.CategoryCode;
                        bom.CategoryName = category?.CategoryName;
                    }

                    var existBoms = mesDb.WorkOrderBoms.AsNoTracking().Where(_ => _.WorkOrderNo == item.WorkOrderNo && _.Valid).ToList();
                    var newBoms = boms.Where(_ => !existBoms.Any(bom => StringUtils.Equals(_.ProductCode, bom.ProductCode) && StringUtils.Equals(_.ProductCompany, bom.ProductCompany))).ToList();
                    var invalidBoms = existBoms.Where(_ => !boms.Any(bom => StringUtils.Equals(_.ProductCode, bom.ProductCode) && StringUtils.Equals(_.ProductCompany, bom.ProductCompany))).ToList();
                    var updateBoms = existBoms.Where(_ => boms.Any(bom => StringUtils.Equals(_.ProductCode, bom.ProductCode) && StringUtils.Equals(_.ProductCompany, bom.ProductCompany))).ToList();
                    mesDb.WorkOrderBoms.AddRange(newBoms);
                    invalidBoms.ForEach(_ =>
                    {
                        mesDb.WorkOrderBoms.Attach(_);
                        _.Valid = false;
                        _.ModifyBy = item.ModifyBy;
                        _.ModifyTime = DateTime.Now;
                    });
                    updateBoms.ForEach(_ =>
                    {
                        var newBom = boms.FirstOrDefault(b => StringUtils.Equals(_.ProductCode, b.ProductCode) && StringUtils.Equals(_.ProductCompany, b.ProductCompany));
                        if (newBom != null &&
                            (_.Count != newBom.Count || _.SingleCount != newBom.SingleCount
                            || !string.Equals(newBom.ProductName, _.ProductName, StringComparison.CurrentCultureIgnoreCase)
                            || !string.Equals(newBom.Specifications, _.Specifications, StringComparison.CurrentCultureIgnoreCase)
                            || !string.Equals(newBom.CategoryCode, _.CategoryCode, StringComparison.CurrentCultureIgnoreCase)
                            || !string.Equals(newBom.CategoryName, _.CategoryName, StringComparison.CurrentCultureIgnoreCase)))
                        {
                            mesDb.WorkOrderBoms.Attach(_);
                            _.ProductName = newBom.ProductName;
                            _.Specifications = newBom.Specifications;
                            _.CategoryCode = newBom.CategoryCode;
                            _.CategoryName = newBom.CategoryName;
                            _.Count = newBom.Count;
                            _.SingleCount = newBom.SingleCount;
                            _.Unit = newBom.Unit;
                            _.ModifyBy = item.ModifyBy;
                            _.ModifyTime = DateTime.Now;
                        }
                    });
                    mesDb.SaveChanges();
                    #endregion

                    #region 生成站点BOM
                    var workOrderSiteBoms = mesDb.ProductSiteBoms.AsNoTracking().Where(_ => _.WorkOrderNo == item.WorkOrderNo && _.Valid).ToList();
                    if (!workOrderSiteBoms.Any())
                    {
                        var globalSiteBoms = mesDb.ProductSiteBoms.AsNoTracking().Where(_ => _.OrderNo == "" && _.WorkOrderNo == "" && _.Valid).ToList();
                        workOrderSiteBoms = Mapper.Map<List<ProductSiteBom>>(Mapper.Map<List<VProductSiteBom>>(globalSiteBoms));
                        workOrderSiteBoms.ForEach(_ =>
                        {
                            _.PkId = 0;
                            _.OrderNo = entity.OrderNo;
                            _.WorkOrderNo = entity.WorkOrderNo;
                            _.CreateTime = DateTime.Now;
                            _.ModifyBy = 0;
                            _.ModifyTime = null;
                        });
                        mesDb.ProductSiteBoms.AddRange(workOrderSiteBoms);
                        mesDb.SaveChanges();
                    }
                    #endregion
                }
                catch (Exception ex)
                {
                    logger.Fatal(ex, $"单个工单导入失败，工单号：{item.WorkOrderNo}，异常信息：{ex.Message}");
                    throw new BizException(1, $"单个工单导入失败，工单号：{item.WorkOrderNo}，异常信息：{ex.Message}");
                }
            }
        }

        /// <summary>
        /// 修复历史BOM
        /// </summary>
        public void RepairWorkOrderBoms()
        {
            var pkid = 183471;
            var categories = mesDb.ProductCategories.AsNoTracking().Where(_ => _.Valid).ToList();
            for (var curId = pkid; curId > 0; curId--)
            {
                try
                {
                    var bom = mesDb.WorkOrderBoms.AsNoTracking().FirstOrDefault(_ => _.PkId == curId && _.Valid);
                    if (bom != null)
                    {
                        var productInfo = mesDb.Products.AsNoTracking().FirstOrDefault(_ => _.ProductCode == bom.ProductCode && _.Valid);
                        if (productInfo == null)
                        {
                            continue;
                        }
                        bom.ProductName = productInfo.ProductName;
                        bom.Specifications = productInfo.Specifications;
                        bom.CreateTime = DateTime.Now;

                        //判定物料大类
                        var categoryCode = productInfo.CategoryCode;
                        while (true)
                        {
                            if (string.IsNullOrWhiteSpace(categoryCode))
                            {
                                break;
                            }
                            var curCategory = categories.FirstOrDefault(_ => StringUtils.Equals(_.CategoryCode, categoryCode));
                            if (curCategory == null)
                            {
                                break;
                            }
                            else if (curCategory.Level <= 2 || string.Equals(curCategory.CategoryName, "电池片", StringComparison.CurrentCultureIgnoreCase))
                            {
                                bom.CategoryCode = curCategory.CategoryCode;
                                bom.CategoryName = curCategory.CategoryName;
                                break;
                            }
                            else
                            {
                                categoryCode = categories.FirstOrDefault(_ => _.PkId == curCategory.ParentId)?.CategoryCode;
                            }
                        }
                        if (!string.IsNullOrWhiteSpace(bom.CategoryName))
                        {
                            var result = mesDb.Database.ExecuteSqlCommand("UPDATE WorkOrderBom SET Specifications = @Specifications, CategoryCode = @CategoryCode, CategoryName = @CategoryName WHERE PkId = @PkId;", new SqlParameter[] {
                            new SqlParameter("@Specifications", bom.Specifications),
                            new SqlParameter("@CategoryCode", bom.CategoryCode),
                            new SqlParameter("@CategoryName", bom.CategoryName),
                            new SqlParameter("@PkId", bom.PkId)
                        });
                            Console.WriteLine("处理BOM：" + curId);
                        }
                    }

                }
                catch (Exception ex)
                {
                    Console.WriteLine("处理BOM异常：" + curId + "_" + ex.Message);
                    Console.WriteLine(ex);
                }
            }
        }

        /// <summary>
        /// 修复历史物料数据
        /// </summary>
        public void RepairMaterias()
        {
            var workOrders = mesDb.WorkOrders.AsNoTracking().Where(_ => _.Valid).OrderByDescending(_ => _.PkId).ToList();
            foreach (var workOrder in workOrders)
            {
                try
                {
                    Console.WriteLine($"{workOrder.WorkOrderNo}:{workOrders.IndexOf(workOrder)}/{workOrders.Count}");

                    var allocateOrderNos = mesDb.AllocateOrders.AsNoTracking().Where(_ => _.WorkOrderNo == workOrder.WorkOrderNo && _.Valid).Select(_ => _.AllocateNo).ToList();
                    var allocateProducts = mesDb.AllocateProducts.AsNoTracking().Where(_ => allocateOrderNos.Contains(_.AllocateNo) && _.Valid).ToList();

                    if (!allocateProducts.Any())
                    {
                        continue;
                    }

                    var battery = allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "电池片")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (battery != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(battery.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BatteryCode = @BatteryCode WHERE WorkOrderNo = @WorkOrderNo AND BatteryCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BatteryCode", battery.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(battery.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BatterySpecs = @BatterySpecs WHERE WorkOrderNo = @WorkOrderNo AND BatterySpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BatterySpecs", battery.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(battery.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BatteryFactory = @BatteryFactory WHERE WorkOrderNo = @WorkOrderNo AND BatteryFactory = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BatteryFactory", battery.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(battery.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BatteryBatchNo = @BatteryBatchNo WHERE WorkOrderNo = @WorkOrderNo AND BatteryBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BatteryBatchNo", battery.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var ribbon = allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "焊带")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (ribbon != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(ribbon.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET RibbonCode = @RibbonCode WHERE WorkOrderNo = @WorkOrderNo AND RibbonCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@RibbonCode", ribbon.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(ribbon.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET RibbonSpecs = @RibbonSpecs WHERE WorkOrderNo = @WorkOrderNo AND RibbonSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@RibbonSpecs", ribbon.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(ribbon.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET RibbonCompany = @RibbonCompany WHERE WorkOrderNo = @WorkOrderNo AND RibbonCompany = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@RibbonCompany", ribbon.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(ribbon.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET RibbonBatchNo = @RibbonBatchNo WHERE WorkOrderNo = @WorkOrderNo AND RibbonBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@RibbonBatchNo", ribbon.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var backPlan = allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "背板")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (backPlan != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(backPlan.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BackPlanCode = @BackPlanCode WHERE WorkOrderNo = @WorkOrderNo AND BackPlanCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BackPlanCode", backPlan.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(backPlan.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BackPlanSpecs = @BackPlanSpecs WHERE WorkOrderNo = @WorkOrderNo AND BackPlanSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BackPlanSpecs", backPlan.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(backPlan.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BackPlanFactory = @BackPlanFactory WHERE WorkOrderNo = @WorkOrderNo AND BackPlanFactory = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BackPlanFactory", backPlan.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(backPlan.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET BackPlanBatchNo = @BackPlanBatchNo WHERE WorkOrderNo = @WorkOrderNo AND BackPlanBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@BackPlanBatchNo", backPlan.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var glass = allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "玻璃")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (glass != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(glass.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET GlassCode = @GlassCode WHERE WorkOrderNo = @WorkOrderNo AND GlassCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@GlassCode", glass.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(glass.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET GlassSpecs = @GlassSpecs WHERE WorkOrderNo = @WorkOrderNo AND GlassSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@GlassSpecs", glass.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(glass.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET GlassFactory = @GlassFactory WHERE WorkOrderNo = @WorkOrderNo AND GlassFactory = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@GlassFactory", glass.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(glass.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET GlassBatchNo = @GlassBatchNo WHERE WorkOrderNo = @WorkOrderNo AND GlassBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@GlassBatchNo", glass.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var eva = allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "EVA")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    eva = eva != null ? eva : allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "POE")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (eva != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(eva.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET EvaCode = @EvaCode WHERE WorkOrderNo = @WorkOrderNo AND EvaCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@EvaCode", eva.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(eva.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET EvaSpecs = @EvaSpecs WHERE WorkOrderNo = @WorkOrderNo AND EvaSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@EvaSpecs", eva.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(eva.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET EvaCompany = @EvaCompany WHERE WorkOrderNo = @WorkOrderNo AND EvaCompany = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@EvaCompany", eva.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(eva.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET EvaBatchNo = @EvaBatchNo WHERE WorkOrderNo = @WorkOrderNo AND EvaBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@EvaBatchNo", eva.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var longFrame = allocateProducts.Where(_ => _.ProductName.Contains("长边框")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (longFrame != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(longFrame.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET LongFrameCode = @LongFrameCode WHERE WorkOrderNo = @WorkOrderNo AND LongFrameCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@LongFrameCode", longFrame.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(longFrame.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET AluFrameSpecs = @AluFrameSpecs WHERE WorkOrderNo = @WorkOrderNo AND AluFrameSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@AluFrameSpecs", longFrame.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(longFrame.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET AluFrameFactory = @AluFrameFactory WHERE WorkOrderNo = @WorkOrderNo AND AluFrameFactory = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@AluFrameFactory", longFrame.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(longFrame.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET AluFrameBatchNo = @AluFrameBatchNo WHERE WorkOrderNo = @WorkOrderNo AND AluFrameBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@AluFrameBatchNo", longFrame.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var shortFrame = allocateProducts.Where(_ => _.ProductName.Contains("短边框")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (shortFrame != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(shortFrame.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET ShortFrameCode = @ShortFrameCode WHERE WorkOrderNo = @WorkOrderNo AND ShortFrameCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@ShortFrameCode", shortFrame.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(shortFrame.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET ShortFrameSpecs = @ShortFrameSpecs WHERE WorkOrderNo = @WorkOrderNo AND ShortFrameSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@ShortFrameSpecs", shortFrame.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(shortFrame.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET ShortFrameCompany = @ShortFrameCompany WHERE WorkOrderNo = @WorkOrderNo AND ShortFrameCompany = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@ShortFrameCompany", shortFrame.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(shortFrame.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET ShortFrameBatchNo = @ShortFrameBatchNo WHERE WorkOrderNo = @WorkOrderNo AND ShortFrameBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@ShortFrameBatchNo", shortFrame.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var box = allocateProducts.Where(_ => StringUtils.Equals(_.CategoryName, "接线盒")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (box != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(box.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET JunBoxCode = @JunBoxCode WHERE WorkOrderNo = @WorkOrderNo AND JunBoxCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@JunBoxCode", box.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result2 = string.IsNullOrWhiteSpace(box.Specifications) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET JunBoxSpecs = @JunBoxSpecs WHERE WorkOrderNo = @WorkOrderNo AND JunBoxSpecs = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@JunBoxSpecs", box.Specifications),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result3 = string.IsNullOrWhiteSpace(box.ProductionCompany) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET JunBoxFactory = @JunBoxFactory WHERE WorkOrderNo = @WorkOrderNo AND JunBoxFactory = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@JunBoxFactory", box.ProductionCompany),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                        var result4 = string.IsNullOrWhiteSpace(box.BatchNo) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET JunBoxBatchNo = @JunBoxBatchNo WHERE WorkOrderNo = @WorkOrderNo AND JunBoxBatchNo = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@JunBoxBatchNo", box.BatchNo),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }

                    var silicagel = allocateProducts.Where(_ => _.CategoryName.Contains("硅胶")).OrderByDescending(_ => _.BatchNo).ThenByDescending(_ => _.ProductionCompany).FirstOrDefault();
                    if (silicagel != null)
                    {
                        var result1 = string.IsNullOrWhiteSpace(silicagel.ProductCode) ? 0 : mesDb.Database.ExecuteSqlCommand($"UPDATE Component SET SilicagelCode = @SilicagelCode WHERE WorkOrderNo = @WorkOrderNo AND SilicagelCode = '';",
                            new SqlParameter[]
                            {
                                new SqlParameter("@SilicagelCode", box.ProductCode),
                                new SqlParameter("@WorkOrderNo", workOrder.WorkOrderNo)
                            });
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"工单修复异常：{workOrder.WorkOrderNo}");
                    Console.WriteLine(ex);
                }
            }
        }

        /// <summary>
        /// 查询未完成的包装
        /// </summary>
        public List<VPack> QueryUnFinishedPacks(string workshopCode)
        {
            var entities = mesDb.Packs.AsNoTracking().Where(_ => _.Valid && _.WorkshopCode == workshopCode && _.PackStatus == PackStatus.Packing).ToList();
            return Mapper.Map<List<VPack>>(entities).OrderBy(_ => _.PackIndex).ToList();
        }

        /// <summary>
        /// 更换打包编号
        /// </summary>
        public void ChangePackNo(VPack model, string newPackNo)
        {
            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.PackStatus != PackStatus.Unpack && _.Valid);
            if (pack == null)
            {
                throw new MultiLanBizException(136001, model.PackNo);
            }
            else if (pack.PackStatus == PackStatus.Unpack)
            {
                throw new MultiLanBizException(123006, model.PackNo);
            }
            else if (mesDb.Packs.AsNoTracking().Count(_ => _.PackNo == newPackNo && _.PackStatus != PackStatus.Unpack && _.Valid) > 0)
            {
                throw new MultiLanBizException(123007, newPackNo);
            }
            mesDb.Packs.Attach(pack);
            pack.PackNo = newPackNo;

            var packProducts = mesDb.PackProducts.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Valid).ToList();
            var components = mesDb.Components.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Valid).ToList();
            packProducts.ForEach(item =>
            {
                mesDb.PackProducts.Attach(item);
                item.PackNo = newPackNo;
                item.ModifyBy = model.ModifyBy;
                item.ModifyTime = DateTime.Now;
            });
            components.ForEach(item =>
            {
                mesDb.Components.Attach(item);
                item.PackNo = newPackNo;
                item.ModifyBy = model.ModifyBy;
                item.ModifyTime = DateTime.Now;
            });

            var inspects = mesDb.InboundInspects.AsNoTracking().Where(_ => _.PackNo == model.PackNo && _.Valid).ToList();
            inspects.ForEach(item =>
            {
                mesDb.InboundInspects.Attach(item);
                item.PackNo = newPackNo;
                item.ModifyBy = model.ModifyBy;
                item.ModifyTime = DateTime.Now;
            });

            if (!string.IsNullOrWhiteSpace(pack.CabinetNo))
            {
                var cabinetPack = mesDb.CabinetPacks.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.Valid);
                if (cabinetPack != null)
                {
                    mesDb.CabinetPacks.Attach(cabinetPack);
                    cabinetPack.PackNo = newPackNo;
                    cabinetPack.ModifyBy = model.ModifyBy;
                    cabinetPack.ModifyTime = DateTime.Now;
                }
            }
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                var user = new UserMgr().GetUser(model.ModifyBy);
                var logs = components.Select(_ => new VOprLog
                {
                    SubjectType = "组件",
                    SubjectNo = _.BarCode,
                    LogName = "更换打包编号",
                    LogStatus = "异常",
                    OpeatorId = model.ModifyBy,
                    OpeatorName = user?.TrueName,
                    LogContent = $"组件更换打包编号，原包装号：{model.PackNo}，新打包编号：{newPackNo}",
                    LogTime = DateTime.Now,
                    CreateBy = model.CreateBy
                }).ToList();
                new OprLogMgr().AddLogs(logs);
            });
        }

        /// <summary>
        /// 更换打包组件
        /// </summary>
        public void ExchangePackProduct(VPackProduct model, string newBarCode)
        {
            if (string.Equals(model.BarCode, newBarCode, StringComparison.CurrentCultureIgnoreCase))
            {
                throw new MultiLanBizException(123008, $"{model.BarCode} / {newBarCode}"); //新老组件条码不可一样
            }

            var component = mesDb.Components.AsNoTracking().FirstOrDefault(_ => _.Valid && _.BarCode == model.BarCode);
            if (component == null)
            {
                throw new MultiLanBizException(102012, model.BarCode);//组件不存在
            }

            var newComponent = mesDb.Components.AsNoTracking().FirstOrDefault(_ => _.Valid && _.BarCode == newBarCode);
            if (newComponent == null)
            {
                throw new MultiLanBizException(102012, newBarCode);//组件不存在
            }

            var pack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.Valid);
            if (pack == null)
            {
                throw new MultiLanBizException(136001, model.PackNo);
            }
            else if (pack.PackStatus == PackStatus.Unpack)
            {
                throw new MultiLanBizException(123006, model.PackNo);
            }

            var packProduct = mesDb.PackProducts.AsNoTracking().FirstOrDefault(_ => _.PackNo == model.PackNo && _.BarCode == model.BarCode && _.Valid);
            if (packProduct == null)
            {
                throw new MultiLanBizException(102033, model.BarCode);//当前条码不在包装中
            }

            mesDb.Components.Attach(component);
            component.PackBatchNo = "";
            component.PackNo = "";
            component.ModifyBy = model.ModifyBy;
            component.ModifyTime = DateTime.Now;

            mesDb.PackProducts.Attach(packProduct);
            packProduct.BarCode = newComponent.BarCode;
            packProduct.WorkshopCode = newComponent.WorkshopCode;
            packProduct.WorkshopName = newComponent.WorkshopName;
            packProduct.OrderNo = newComponent.OrderNo;
            packProduct.WorkOrderNo = newComponent.WorkOrderNo;
            packProduct.ProductCode = newComponent.ProductCode;
            packProduct.ProductName = newComponent.ProductName;
            packProduct.ModifyBy = model.ModifyBy;
            packProduct.ModifyTime = DateTime.Now;

            if (pack.PackInspectStatus == PackInboundInspectStatus.UnInspected)
            {
                var inspect = mesDb.InboundInspects.AsNoTracking().FirstOrDefault(_ => _.PackNo == pack.PackNo && _.Status == PackInboundInspectStatus.UnInspected && _.Valid);
                if (inspect != null)
                {
                    var inspectProduct = mesDb.InboundInspectProducts.AsNoTracking().FirstOrDefault(_ => _.InspectId == inspect.PkId && _.BarCode == model.BarCode && _.Valid);
                    if (inspectProduct != null)
                    {
                        mesDb.InboundInspectProducts.Attach(inspectProduct);
                        inspectProduct.BarCode = newBarCode;
                        inspectProduct.OrderNo = newComponent.OrderNo;
                        inspectProduct.WorkOrderNo = newComponent.WorkOrderNo;
                        inspectProduct.QLevel = newComponent.QLevel;
                        inspectProduct.BoxImage = newComponent.BoxImage;
                        inspectProduct.IvImage = newComponent.IvImage;
                        inspectProduct.EL2Image = newComponent.EL2Image;
                        inspectProduct.ModifyBy = model.ModifyBy;
                        inspectProduct.ModifyTime = DateTime.Now;
                    }
                }
            }

            if (!string.IsNullOrWhiteSpace(newComponent.PackNo))
            {
                var newPack = mesDb.Packs.AsNoTracking().FirstOrDefault(_ => _.PackNo == newComponent.PackNo && _.Valid);
                if (newPack != null)
                {
                    var newPackProduct = mesDb.PackProducts.AsNoTracking().FirstOrDefault(_ => _.PackNo == newPack.PackNo && _.BarCode == newBarCode && _.Valid);
                    if (newPackProduct != null)
                    {
                        mesDb.Packs.Attach(newPack);
                        newPack.Quantity = newPack.Quantity - 1;
                        newPack.ModifyBy = model.ModifyBy;
                        newPack.ModifyTime = DateTime.Now;

                        mesDb.PackProducts.Attach(newPackProduct);
                        newPackProduct.Valid = false;
                        newPackProduct.ModifyBy = model.ModifyBy;
                        newPackProduct.ModifyTime = DateTime.Now;
                    }
                    if (newPack.PackInspectStatus == PackInboundInspectStatus.UnInspected)
                    {
                        var newInspect = mesDb.InboundInspects.AsNoTracking().FirstOrDefault(_ => _.PackNo == newPack.PackNo && _.Status == PackInboundInspectStatus.UnInspected && _.Valid);
                        if (newInspect != null)
                        {
                            var newInspectProduct = mesDb.InboundInspectProducts.AsNoTracking().FirstOrDefault(_ => _.InspectId == newInspect.PkId && _.BarCode == newBarCode && _.Valid);
                            if (newInspectProduct != null)
                            {
                                mesDb.InboundInspectProducts.Attach(newInspectProduct);
                                newInspectProduct.Valid = false;
                                newInspectProduct.ModifyBy = model.ModifyBy;
                                newInspectProduct.ModifyTime = DateTime.Now;
                            }
                        }
                    }
                }
            }

            mesDb.Components.Attach(newComponent);
            newComponent.PackBatchNo = pack.PackBatchNo;
            newComponent.PackNo = pack.PackNo;
            newComponent.ModifyBy = model.ModifyBy;
            newComponent.ModifyTime = DateTime.Now;
            mesDb.SaveChanges();

            new TaskFactory().StartNew(() =>
            {
                var user = new UserMgr().GetUser(model.ModifyBy);
                new OprLogMgr().AddLog(new VOprLog
                {
                    SubjectType = "组件",
                    SubjectNo = component.BarCode,
                    LogName = "替换打包编号",
                    LogStatus = "异常",
                    OpeatorId = model.ModifyBy,
                    OpeatorName = user?.TrueName,
                    LogContent = $"原包装号：{pack.PackNo}，替换后的新组件：{newBarCode}",
                    LogTime = DateTime.Now,
                    CreateBy = model.CreateBy
                });
                new OprLogMgr().AddLog(new VOprLog
                {
                    SubjectType = "组件",
                    SubjectNo = newComponent.BarCode,
                    LogName = "替换打包编号",
                    LogStatus = "异常",
                    OpeatorId = model.ModifyBy,
                    OpeatorName = user?.TrueName,
                    LogContent = $"包装号：{pack.PackNo}，替换前的组件：{model.BarCode}",
                    LogTime = DateTime.Now,
                    CreateBy = model.CreateBy
                });
            });
        }
    }
}
